<!DOCTYPE html><html lang="zh-CN" data-theme="light"><head><meta charset="UTF-8"><meta http-equiv="X-UA-Compatible" content="IE=edge"><meta name="viewport" content="width=device-width,initial-scale=1"><title>微服务框架 | 逝水无痕の博客</title><meta name="keywords" content="java,springcloud"><meta name="author" content="逝水无痕"><meta name="copyright" content="逝水无痕"><meta name="format-detection" content="telephone=no"><meta name="theme-color" content="#ffffff"><meta name="description" content="微服务框架[toc] 一、SpringCloud介绍1.1 微服务架构 https:&#x2F;&#x2F;martinfowler.com&#x2F;articles&#x2F;microservices.html 微服务架构提出者:马丁福勒   简而言之，微服务体系结构[样式 1]是一种将单个应用程序开发为一组小型服务的方法，每个应用程序在自己的进程中运行，并与轻量级机制（通常是 HTTP 资源 API）通信。这些服务围绕业务功能构">
<meta property="og:type" content="article">
<meta property="og:title" content="微服务框架">
<meta property="og:url" content="https://hexo.zyjblogs.cn/posts/java/springcloud/1.html">
<meta property="og:site_name" content="逝水无痕の博客">
<meta property="og:description" content="微服务框架[toc] 一、SpringCloud介绍1.1 微服务架构 https:&#x2F;&#x2F;martinfowler.com&#x2F;articles&#x2F;microservices.html 微服务架构提出者:马丁福勒   简而言之，微服务体系结构[样式 1]是一种将单个应用程序开发为一组小型服务的方法，每个应用程序在自己的进程中运行，并与轻量级机制（通常是 HTTP 资源 API）通信。这些服务围绕业务功能构">
<meta property="og:locale" content="zh_CN">
<meta property="og:image" content="https://cdn.jsdelivr.net/npm/butterfly-extsrc@1/img/default.jpg">
<meta property="article:published_time" content="2021-08-06T16:00:00.000Z">
<meta property="article:modified_time" content="2022-02-08T01:32:27.902Z">
<meta property="article:author" content="逝水无痕">
<meta property="article:tag" content="java">
<meta property="article:tag" content="springcloud">
<meta name="twitter:card" content="summary">
<meta name="twitter:image" content="https://cdn.jsdelivr.net/npm/butterfly-extsrc@1/img/default.jpg"><link rel="shortcut icon" href="/img/favicon.png"><link rel="canonical" href="https://hexo.zyjblogs.cn/posts/java/springcloud/1"><link rel="preconnect" href="//cdn.jsdelivr.net"/><link rel="preconnect" href="//hm.baidu.com"/><link rel="preconnect" href="//busuanzi.ibruce.info"/><link rel="stylesheet" href="/css/index.css"><link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/@fortawesome/fontawesome-free/css/all.min.css" media="print" onload="this.media='all'"><link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/node-snackbar/dist/snackbar.min.css" media="print" onload="this.media='all'"><script>var _hmt = _hmt || [];
(function() {
  var hm = document.createElement("script");
  hm.src = "https://hm.baidu.com/hm.js?6edd69cc926242ec43e7194677fb8040";
  var s = document.getElementsByTagName("script")[0]; 
  s.parentNode.insertBefore(hm, s);
})();
</script><script>const GLOBAL_CONFIG = { 
  root: '/',
  algolia: undefined,
  localSearch: {"path":"search.xml","languages":{"hits_empty":"找不到您查询的内容：${query}"}},
  translate: undefined,
  noticeOutdate: undefined,
  highlight: {"plugin":"highlighjs","highlightCopy":true,"highlightLang":true,"highlightHeightLimit":false},
  copy: {
    success: '复制成功',
    error: '复制错误',
    noSupport: '浏览器不支持'
  },
  relativeDate: {
    homepage: false,
    post: false
  },
  runtime: '天',
  date_suffix: {
    just: '刚刚',
    min: '分钟前',
    hour: '小时前',
    day: '天前',
    month: '个月前'
  },
  copyright: undefined,
  lightbox: 'fancybox',
  Snackbar: {"chs_to_cht":"你已切换为繁体","cht_to_chs":"你已切换为简体","day_to_night":"你已切换为深色模式","night_to_day":"你已切换为浅色模式","bgLight":"#49b1f5","bgDark":"#121212","position":"bottom-left"},
  source: {
    jQuery: 'https://cdn.jsdelivr.net/npm/jquery@latest/dist/jquery.min.js',
    justifiedGallery: {
      js: 'https://cdn.jsdelivr.net/npm/justifiedGallery/dist/js/jquery.justifiedGallery.min.js',
      css: 'https://cdn.jsdelivr.net/npm/justifiedGallery/dist/css/justifiedGallery.min.css'
    },
    fancybox: {
      js: 'https://cdn.jsdelivr.net/npm/@fancyapps/fancybox@latest/dist/jquery.fancybox.min.js',
      css: 'https://cdn.jsdelivr.net/npm/@fancyapps/fancybox@latest/dist/jquery.fancybox.min.css'
    }
  },
  isPhotoFigcaption: false,
  islazyload: false,
  isanchor: false
}</script><script id="config-diff">var GLOBAL_CONFIG_SITE = {
  title: '微服务框架',
  isPost: true,
  isHome: false,
  isHighlightShrink: false,
  isToc: true,
  postUpdate: '2022-02-08 09:32:27'
}</script><noscript><style type="text/css">
  #nav {
    opacity: 1
  }
  .justified-gallery img {
    opacity: 1
  }

  #recent-posts time,
  #post-meta time {
    display: inline !important
  }
</style></noscript><script>(win=>{
    win.saveToLocal = {
      set: function setWithExpiry(key, value, ttl) {
        if (ttl === 0) return
        const now = new Date()
        const expiryDay = ttl * 86400000
        const item = {
          value: value,
          expiry: now.getTime() + expiryDay,
        }
        localStorage.setItem(key, JSON.stringify(item))
      },

      get: function getWithExpiry(key) {
        const itemStr = localStorage.getItem(key)

        if (!itemStr) {
          return undefined
        }
        const item = JSON.parse(itemStr)
        const now = new Date()

        if (now.getTime() > item.expiry) {
          localStorage.removeItem(key)
          return undefined
        }
        return item.value
      }
    }
  
    win.getScript = url => new Promise((resolve, reject) => {
      const script = document.createElement('script')
      script.src = url
      script.async = true
      script.onerror = reject
      script.onload = script.onreadystatechange = function() {
        const loadState = this.readyState
        if (loadState && loadState !== 'loaded' && loadState !== 'complete') return
        script.onload = script.onreadystatechange = null
        resolve()
      }
      document.head.appendChild(script)
    })
  
      win.activateDarkMode = function () {
        document.documentElement.setAttribute('data-theme', 'dark')
        if (document.querySelector('meta[name="theme-color"]') !== null) {
          document.querySelector('meta[name="theme-color"]').setAttribute('content', '#0d0d0d')
        }
      }
      win.activateLightMode = function () {
        document.documentElement.setAttribute('data-theme', 'light')
        if (document.querySelector('meta[name="theme-color"]') !== null) {
          document.querySelector('meta[name="theme-color"]').setAttribute('content', '#ffffff')
        }
      }
      const t = saveToLocal.get('theme')
    
          if (t === 'dark') activateDarkMode()
          else if (t === 'light') activateLightMode()
        
      const asideStatus = saveToLocal.get('aside-status')
      if (asideStatus !== undefined) {
        if (asideStatus === 'hide') {
          document.documentElement.classList.add('hide-aside')
        } else {
          document.documentElement.classList.remove('hide-aside')
        }
      }
    
    const detectApple = () => {
      if (GLOBAL_CONFIG_SITE.isHome && /iPad|iPhone|iPod|Macintosh/.test(navigator.userAgent)){
        document.documentElement.classList.add('apple')
      }
    }
    detectApple()
    document.addEventListener('pjax:complete', detectApple)})(window)</script><link rel="stylesheet" href="_static/css/background.css"><meta name="generator" content="Hexo 5.4.0"><link rel="alternate" href="/atom.xml" title="逝水无痕の博客" type="application/atom+xml">
<link rel="alternate" href="/rss2.xml" title="逝水无痕の博客" type="application/rss+xml">
</head><body><div id="loading-box"><div class="loading-left-bg"></div><div class="loading-right-bg"></div><div class="spinner-box"><div class="configure-border-1"><div class="configure-core"></div></div><div class="configure-border-2"><div class="configure-core"></div></div><div class="loading-word">加载中...</div></div></div><div id="web_bg"></div><div id="sidebar"><div id="menu-mask"></div><div id="sidebar-menus"><div class="avatar-img is-center"><img src="https://zyjblogs.cn/logo.jpg" onerror="onerror=null;src='/img/friend_404.gif'" alt="avatar"/></div><div class="site-data"><div class="data-item is-center"><div class="data-item-link"><a href="/archives/"><div class="headline">文章</div><div class="length-num">11</div></a></div></div><div class="data-item is-center"><div class="data-item-link"><a href="/tags/"><div class="headline">标签</div><div class="length-num">8</div></a></div></div><div class="data-item is-center"><div class="data-item-link"><a href="/categories/"><div class="headline">分类</div><div class="length-num">5</div></a></div></div></div><hr/><div class="menus_items"><div class="menus_item"><a class="site-page" href="/"><i class="fa-fw fas fa-home"></i><span> 首页</span></a></div><div class="menus_item"><a class="site-page" href="/archives/"><i class="fa-fw fas fa-archive"></i><span> 归档</span></a></div><div class="menus_item"><a class="site-page" href="/tags/"><i class="fa-fw fas fa-tags"></i><span> 标签</span></a></div><div class="menus_item"><a class="site-page" href="javascript:void(0);"><i class="fa-fw fas fa-list"></i><span> 媒体</span><i class="fas fa-chevron-down expand"></i></a><ul class="menus_item_child"><li><a class="site-page child" href="/bangumis"><i class="fa-fw fa-fw fab fa-youtube"></i><span> 番剧</span></a></li></ul></div><div class="menus_item"><a class="site-page" href="/categories/"><i class="fa-fw fas fa-folder-open"></i><span> 分类</span></a></div><div class="menus_item"><a class="site-page" href="/link/"><i class="fa-fw fas fa-link"></i><span> 友链</span></a></div><div class="menus_item"><a class="site-page" href="/about/"><i class="fa-fw fas fa-heart"></i><span> 关于</span></a></div></div></div></div><div class="post" id="body-wrap"><header class="post-bg" id="page-header" style="background-image: url('https://cdn.jsdelivr.net/npm/butterfly-extsrc@1/img/default.jpg')"><nav id="nav"><span id="blog_name"><a id="site-name" href="/">逝水无痕の博客</a></span><div id="menus"><div id="search-button"><a class="site-page social-icon search"><i class="fas fa-search fa-fw"></i><span> 搜索</span></a></div><div class="menus_items"><div class="menus_item"><a class="site-page" href="/"><i class="fa-fw fas fa-home"></i><span> 首页</span></a></div><div class="menus_item"><a class="site-page" href="/archives/"><i class="fa-fw fas fa-archive"></i><span> 归档</span></a></div><div class="menus_item"><a class="site-page" href="/tags/"><i class="fa-fw fas fa-tags"></i><span> 标签</span></a></div><div class="menus_item"><a class="site-page" href="javascript:void(0);"><i class="fa-fw fas fa-list"></i><span> 媒体</span><i class="fas fa-chevron-down expand"></i></a><ul class="menus_item_child"><li><a class="site-page child" href="/bangumis"><i class="fa-fw fa-fw fab fa-youtube"></i><span> 番剧</span></a></li></ul></div><div class="menus_item"><a class="site-page" href="/categories/"><i class="fa-fw fas fa-folder-open"></i><span> 分类</span></a></div><div class="menus_item"><a class="site-page" href="/link/"><i class="fa-fw fas fa-link"></i><span> 友链</span></a></div><div class="menus_item"><a class="site-page" href="/about/"><i class="fa-fw fas fa-heart"></i><span> 关于</span></a></div></div><div id="toggle-menu"><a class="site-page"><i class="fas fa-bars fa-fw"></i></a></div></div></nav><div id="post-info"><h1 class="post-title">微服务框架</h1><div id="post-meta"><div class="meta-firstline"><span class="post-meta-date"><i class="far fa-calendar-alt fa-fw post-meta-icon"></i><span class="post-meta-label">发表于</span><time class="post-meta-date-created" datetime="2021-08-06T16:00:00.000Z" title="发表于 2021-08-07 00:00:00">2021-08-07</time><span class="post-meta-separator">|</span><i class="fas fa-history fa-fw post-meta-icon"></i><span class="post-meta-label">更新于</span><time class="post-meta-date-updated" datetime="2022-02-08T01:32:27.902Z" title="更新于 2022-02-08 09:32:27">2022-02-08</time></span><span class="post-meta-categories"><span class="post-meta-separator">|</span><i class="fas fa-inbox fa-fw post-meta-icon"></i><a class="post-meta-categories" href="/categories/java/">java</a></span></div><div class="meta-secondline"><span class="post-meta-separator">|</span><span class="post-meta-wordcount"><i class="far fa-file-word fa-fw post-meta-icon"></i><span class="post-meta-label">字数总计:</span><span class="word-count">8.4k</span><span class="post-meta-separator">|</span><i class="far fa-clock fa-fw post-meta-icon"></i><span class="post-meta-label">阅读时长:</span><span>36分钟</span></span><span class="post-meta-separator">|</span><span class="post-meta-pv-cv" id="" data-flag-title="微服务框架"><i class="far fa-eye fa-fw post-meta-icon"></i><span class="post-meta-label">阅读量:</span><span id="busuanzi_value_page_pv"></span></span></div></div></div></header><main class="layout" id="content-inner"><div id="post"><article class="post-content" id="article-container"><h1 id="微服务框架"><a href="#微服务框架" class="headerlink" title="微服务框架"></a>微服务框架</h1><p>[toc]</p>
<h2 id="一、SpringCloud介绍"><a href="#一、SpringCloud介绍" class="headerlink" title="一、SpringCloud介绍"></a>一、SpringCloud介绍</h2><h3 id="1-1-微服务架构"><a href="#1-1-微服务架构" class="headerlink" title="1.1 微服务架构"></a>1.1 微服务架构</h3><blockquote>
<p><a target="_blank" rel="noopener" href="https://martinfowler.com/articles/microservices.html">https://martinfowler.com/articles/microservices.html</a></p>
<p>微服务架构提出者:马丁福勒</p>
</blockquote>
<blockquote>
<p>简而言之，微服务体系结构[样式 <a target="_blank" rel="noopener" href="https://martinfowler.com/articles/microservices.html#footnote-etymology">1]</a>是一种将单个应用程序开发为一组小型服务的方法，每个应用程序在自己的进程中运行，并与轻量级机制（通常是 HTTP 资源 API）通信。这些服务围绕业务功能构建，可通过全自动部署机制独立部署。这些服务的集中管理最少，可能以不同的编程语言编写，并使用不同的数据存储技术。</p>
</blockquote>
<h3 id="1-2-SpringCloud介绍"><a href="#1-2-SpringCloud介绍" class="headerlink" title="1.2 SpringCloud介绍"></a>1.2 SpringCloud介绍</h3><blockquote>
<p>SpringCloud是微服务架构落地的一套技术栈</p>
<p>SpringCloud中的大多数技术都是基于Netflix公司的技术进行第二次开发。</p>
<p>1、SpringCloud的中文社区网站：<a target="_blank" rel="noopener" href="http://springcloud.cn/">http://springcloud.cn/</a></p>
<p>2、SpringCloud的中文网 ：<a target="_blank" rel="noopener" href="http://springcloud.cc/">http://springcloud.cc/</a></p>
<p>八个技术点：</p>
<p>1、Eureka - 服务的注册与发现</p>
<p>2、Robbn - 服务之间的负载均衡</p>
<p>3、Feign - 服务之间的通讯</p>
<p>4、Hystrix - 服务的线程隔离及其熔断器</p>
<p>5、Zuul - 服务网关</p>
<p>6、Stream - 实现MQ的使用</p>
<p>7、Config - 动态配置</p>
<p>8、 Sleuth - 服务追踪</p>
</blockquote>
<h2 id="二、服务的注册与发现-Eureka"><a href="#二、服务的注册与发现-Eureka" class="headerlink" title="二、服务的注册与发现-Eureka"></a>二、服务的注册与发现-Eureka</h2><h3 id="2-1-引言"><a href="#2-1-引言" class="headerlink" title="2.1 引言"></a>2.1 引言</h3><blockquote>
<p>Eureka就是帮助我们维护所有服务的信息，以便服务之间的相互调用</p>
</blockquote>
<p><img src="/posts/java/springcloud/1/images/1605019839175.png" alt="1605019839175"></p>
<h3 id="2-2-Eureka的快速入门"><a href="#2-2-Eureka的快速入门" class="headerlink" title="2.2 Eureka的快速入门"></a>2.2 Eureka的快速入门</h3><h4 id="2-2-1-创建EurekaServer"><a href="#2-2-1-创建EurekaServer" class="headerlink" title="2.2.1 创建EurekaServer"></a>2.2.1 创建EurekaServer</h4><blockquote>
<p>1、创建一个父工程，并且在父工程中指定SpringCloud版本，并且将packaing修改为pom</p>
</blockquote>
<figure class="highlight xml"><table><tr><td class="code"><pre><span class="line"><span class="tag">&lt;<span class="name">packaging</span>&gt;</span>pom<span class="tag">&lt;/<span class="name">packaging</span>&gt;</span></span><br><span class="line"></span><br><span class="line"><span class="tag">&lt;<span class="name">properties</span>&gt;</span></span><br><span class="line">   <span class="tag">&lt;<span class="name">java.version</span>&gt;</span>1.8<span class="tag">&lt;/<span class="name">java.version</span>&gt;</span></span><br><span class="line">   <span class="tag">&lt;<span class="name">spring.cloud-version</span>&gt;</span>Hoxton.SR8<span class="tag">&lt;/<span class="name">spring.cloud-version</span>&gt;</span></span><br><span class="line"><span class="tag">&lt;/<span class="name">properties</span>&gt;</span></span><br><span class="line"><span class="tag">&lt;<span class="name">dependencyManagement</span>&gt;</span></span><br><span class="line">   <span class="tag">&lt;<span class="name">dependencies</span>&gt;</span></span><br><span class="line">      <span class="tag">&lt;<span class="name">dependency</span>&gt;</span></span><br><span class="line">          <span class="tag">&lt;<span class="name">groupId</span>&gt;</span>org.springframework.cloud<span class="tag">&lt;/<span class="name">groupId</span>&gt;</span></span><br><span class="line">            <span class="tag">&lt;<span class="name">artifactId</span>&gt;</span>spring-cloud-dependencies<span class="tag">&lt;/<span class="name">artifactId</span>&gt;</span></span><br><span class="line">            <span class="tag">&lt;<span class="name">version</span>&gt;</span>$&#123;spring.cloud-version&#125;<span class="tag">&lt;/<span class="name">version</span>&gt;</span></span><br><span class="line">            <span class="tag">&lt;<span class="name">type</span>&gt;</span>pom<span class="tag">&lt;/<span class="name">type</span>&gt;</span></span><br><span class="line">            <span class="tag">&lt;<span class="name">scope</span>&gt;</span>import<span class="tag">&lt;/<span class="name">scope</span>&gt;</span></span><br><span class="line">        <span class="tag">&lt;/<span class="name">dependency</span>&gt;</span></span><br><span class="line">    <span class="tag">&lt;/<span class="name">dependencies</span>&gt;</span></span><br><span class="line"><span class="tag">&lt;/<span class="name">dependencyManagement</span>&gt;</span></span><br></pre></td></tr></table></figure>

<blockquote>
<p>2、创建eureka的server，创建springboot工程，并且导入依赖，再启动类中添<code>@EnableEurekaServer</code>注解和编写yml文件</p>
</blockquote>
<blockquote>
<p>2.1、导入依赖</p>
</blockquote>
<figure class="highlight xml"><table><tr><td class="code"><pre><span class="line"><span class="tag">&lt;<span class="name">dependencies</span>&gt;</span></span><br><span class="line">   <span class="tag">&lt;<span class="name">dependency</span>&gt;</span></span><br><span class="line">      <span class="tag">&lt;<span class="name">groupId</span>&gt;</span>org.springframework.boot<span class="tag">&lt;/<span class="name">groupId</span>&gt;</span></span><br><span class="line">      <span class="tag">&lt;<span class="name">artifactId</span>&gt;</span>spring-boot-starter-web<span class="tag">&lt;/<span class="name">artifactId</span>&gt;</span></span><br><span class="line">   <span class="tag">&lt;/<span class="name">dependency</span>&gt;</span></span><br><span class="line">   <span class="tag">&lt;<span class="name">dependency</span>&gt;</span></span><br><span class="line">       <span class="tag">&lt;<span class="name">groupId</span>&gt;</span>org.springframework.cloud<span class="tag">&lt;/<span class="name">groupId</span>&gt;</span></span><br><span class="line">       <span class="tag">&lt;<span class="name">artifactId</span>&gt;</span>spring-cloud-starter-netflix-eureka-server<span class="tag">&lt;/<span class="name">artifactId</span>&gt;</span></span><br><span class="line">   <span class="tag">&lt;/<span class="name">dependency</span>&gt;</span></span><br><span class="line"><span class="tag">&lt;/<span class="name">dependencies</span>&gt;</span></span><br></pre></td></tr></table></figure>

<blockquote>
<p>2.2、启动类添加注解</p>
</blockquote>
<figure class="highlight java"><table><tr><td class="code"><pre><span class="line"><span class="meta">@EnableEurekaServer</span></span><br><span class="line"><span class="meta">@SpringBootApplication</span></span><br><span class="line"><span class="keyword">public</span> <span class="class"><span class="keyword">class</span> <span class="title">EurekaApplication</span> </span>&#123;</span><br><span class="line">    <span class="function"><span class="keyword">public</span> <span class="keyword">static</span> <span class="keyword">void</span> <span class="title">main</span><span class="params">(String[] args)</span> </span>&#123;</span><br><span class="line">        SpringApplication.run(EurekaApplication.class,args);</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>

<blockquote>
<p>2.3 编写yml配置文件</p>
</blockquote>
<figure class="highlight yml"><table><tr><td class="code"><pre><span class="line"><span class="attr">server:</span></span><br><span class="line">  <span class="attr">port:</span> <span class="number">8761</span></span><br><span class="line"></span><br><span class="line"><span class="attr">eureka:</span></span><br><span class="line">  <span class="attr">instance:</span></span><br><span class="line">    <span class="attr">hostname:</span> <span class="string">localhost</span></span><br><span class="line">  <span class="attr">client:</span></span><br><span class="line">    <span class="comment">#当前的eureka是单机版的</span></span><br><span class="line">    <span class="attr">registerWithEureka:</span> <span class="literal">false</span></span><br><span class="line">    <span class="attr">fetchRegistry:</span> <span class="literal">false</span></span><br><span class="line">    <span class="attr">serviceUrl:</span></span><br><span class="line">      <span class="attr">defaultZone:</span> <span class="string">http://$&#123;eureka.instance.hostname&#125;:$&#123;server.port&#125;/eureka/</span></span><br></pre></td></tr></table></figure>

<h4 id="2-2-2-创建EurekaClient"><a href="#2-2-2-创建EurekaClient" class="headerlink" title="2.2.2 创建EurekaClient"></a>2.2.2 创建EurekaClient</h4><blockquote>
<p>1、创建Maven工程，修改为SpringBoot</p>
</blockquote>
<blockquote>
<p>2、导入依赖</p>
</blockquote>
<figure class="highlight xml"><table><tr><td class="code"><pre><span class="line"><span class="tag">&lt;<span class="name">dependency</span>&gt;</span></span><br><span class="line">    <span class="tag">&lt;<span class="name">groupId</span>&gt;</span>org.springframework.cloud<span class="tag">&lt;/<span class="name">groupId</span>&gt;</span></span><br><span class="line">    <span class="tag">&lt;<span class="name">artifactId</span>&gt;</span>spring-cloud-starter-netflix-eureka-client<span class="tag">&lt;/<span class="name">artifactId</span>&gt;</span></span><br><span class="line"><span class="tag">&lt;/<span class="name">dependency</span>&gt;</span></span><br></pre></td></tr></table></figure>

<blockquote>
<p>3、在启动类上添加注解<code>@EnableEurekaClient</code></p>
</blockquote>
<figure class="highlight java"><table><tr><td class="code"><pre><span class="line"><span class="meta">@EnableEurekaClient</span></span><br><span class="line"><span class="meta">@SpringBootApplication</span></span><br><span class="line"><span class="keyword">public</span> <span class="class"><span class="keyword">class</span> <span class="title">CustomerApplication</span> </span>&#123;</span><br><span class="line">    <span class="function"><span class="keyword">public</span> <span class="keyword">static</span> <span class="keyword">void</span> <span class="title">main</span><span class="params">(String[] args)</span> </span>&#123;</span><br><span class="line">        SpringApplication.run(CustomerApplication.class,args);</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>

<blockquote>
<p>4、编写配置文件</p>
</blockquote>
<figure class="highlight yml"><table><tr><td class="code"><pre><span class="line"><span class="comment">#指定Eureka服务地址</span></span><br><span class="line"><span class="attr">eureka:</span></span><br><span class="line">  <span class="attr">client:</span></span><br><span class="line">    <span class="attr">service-url:</span></span><br><span class="line">      <span class="attr">defaultZone:</span> <span class="string">http://localhost:8761/eureka</span></span><br><span class="line"></span><br><span class="line"><span class="comment">#指定服务名称</span></span><br><span class="line"><span class="attr">spring:</span></span><br><span class="line">  <span class="attr">application:</span></span><br><span class="line">    <span class="attr">name:</span> <span class="string">CUSTOMER</span></span><br></pre></td></tr></table></figure>

<p><img src="/posts/java/springcloud/1/images/image-20201111095518705.png" alt="image-20201111095518705"></p>
<h4 id="2-2-3-测试Eureka"><a href="#2-2-3-测试Eureka" class="headerlink" title="2.2.3 测试Eureka"></a>2.2.3 测试Eureka</h4><blockquote>
<p>1、创建了一个Search搜索模块，并且注册到Eureka</p>
</blockquote>
<blockquote>
<p>2、使用EurekaClient的对象获取服务信息</p>
</blockquote>
<figure class="highlight java"><table><tr><td class="code"><pre><span class="line"><span class="meta">@Autowired</span></span><br><span class="line">    <span class="keyword">private</span> EurekaClient eurekaClient;</span><br></pre></td></tr></table></figure>

<blockquote>
<p>3、创建RestTemplate</p>
</blockquote>
<figure class="highlight java"><table><tr><td class="code"><pre><span class="line"><span class="meta">@Configuration</span></span><br><span class="line"><span class="keyword">public</span> <span class="class"><span class="keyword">class</span> <span class="title">RestTemplateConfig</span> </span>&#123;</span><br><span class="line"></span><br><span class="line">    <span class="meta">@Bean</span></span><br><span class="line">    <span class="function"><span class="keyword">public</span>  RestTemplate <span class="title">restTemplate</span><span class="params">()</span> </span>&#123;</span><br><span class="line">        <span class="keyword">return</span> <span class="keyword">new</span> RestTemplate();</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>

<blockquote>
<p>4、使用RestTemplate调用</p>
</blockquote>
<figure class="highlight java"><table><tr><td class="code"><pre><span class="line"><span class="meta">@GetMapping(&quot;/customer&quot;)</span></span><br><span class="line"><span class="function"><span class="keyword">public</span> String <span class="title">customer</span><span class="params">()</span> </span>&#123;</span><br><span class="line">    <span class="comment">//1. 通过eurekaClient 获取到SEARCH服务的信息</span></span><br><span class="line">    InstanceInfo info = eurekaClient.getNextServerFromEureka(<span class="string">&quot;SEARCH&quot;</span>, <span class="keyword">false</span>);</span><br><span class="line">    <span class="comment">//2. 获取到访问的地址</span></span><br><span class="line">    String url = info.getHomePageUrl();</span><br><span class="line">    System.out.println(url);</span><br><span class="line">    <span class="comment">//3. 通过restTemplate访问</span></span><br><span class="line">    String result = restTemplate.getForObject(url + <span class="string">&quot;/search&quot;</span>, String.class);</span><br><span class="line">    <span class="comment">//4. 返回</span></span><br><span class="line">    <span class="keyword">return</span> result;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>

<h3 id="2-3-Eureka的安全性"><a href="#2-3-Eureka的安全性" class="headerlink" title="2.3 Eureka的安全性"></a>2.3 Eureka的安全性</h3><blockquote>
<p>实现Eureka认证</p>
</blockquote>
<blockquote>
<p>1、导入依赖</p>
</blockquote>
<figure class="highlight xml"><table><tr><td class="code"><pre><span class="line"><span class="tag">&lt;<span class="name">dependency</span>&gt;</span></span><br><span class="line">    <span class="tag">&lt;<span class="name">groupId</span>&gt;</span>org.springframework.boot<span class="tag">&lt;/<span class="name">groupId</span>&gt;</span></span><br><span class="line">    <span class="tag">&lt;<span class="name">artifactId</span>&gt;</span>spring-boot-starter-security<span class="tag">&lt;/<span class="name">artifactId</span>&gt;</span></span><br><span class="line"><span class="tag">&lt;/<span class="name">dependency</span>&gt;</span></span><br></pre></td></tr></table></figure>

<blockquote>
<p>2、编写配置类</p>
</blockquote>
<figure class="highlight java"><table><tr><td class="code"><pre><span class="line"><span class="meta">@EnableWebSecurity</span></span><br><span class="line"><span class="class"><span class="keyword">class</span> <span class="title">WebSecurityConfig</span> <span class="keyword">extends</span> <span class="title">WebSecurityConfigurerAdapter</span> </span>&#123;</span><br><span class="line"></span><br><span class="line">    <span class="meta">@Override</span></span><br><span class="line">    <span class="function"><span class="keyword">protected</span> <span class="keyword">void</span> <span class="title">configure</span><span class="params">(HttpSecurity http)</span> <span class="keyword">throws</span> Exception </span>&#123;</span><br><span class="line">        <span class="comment">//忽略掉/eureka/**路径</span></span><br><span class="line">        http.csrf().ignoringAntMatchers(<span class="string">&quot;/eureka/**&quot;</span>);</span><br><span class="line">        <span class="keyword">super</span>.configure(http);</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>

<blockquote>
<p>3、编写配置文件,配置用户密码</p>
</blockquote>
<figure class="highlight yml"><table><tr><td class="code"><pre><span class="line"><span class="comment">#指定用户名密码</span></span><br><span class="line"><span class="attr">spring:</span></span><br><span class="line">  <span class="attr">security:</span></span><br><span class="line">    <span class="attr">user:</span></span><br><span class="line">      <span class="attr">name:</span> <span class="string">root</span></span><br><span class="line">      <span class="attr">password:</span> <span class="string">root</span></span><br></pre></td></tr></table></figure>

<blockquote>
<p>4、其他服务想注册到Eureka上需要添加用户名密码</p>
</blockquote>
<figure class="highlight yml"><table><tr><td class="code"><pre><span class="line"><span class="comment">#指定Eureka服务地址</span></span><br><span class="line"><span class="attr">eureka:</span></span><br><span class="line">  <span class="attr">client:</span></span><br><span class="line">    <span class="attr">service-url:</span></span><br><span class="line">      <span class="attr">defaultZone:</span> <span class="string">http://用户名:密码@localhost:8761/eureka</span></span><br></pre></td></tr></table></figure>

<h3 id="2-4-Eureka的高可用性"><a href="#2-4-Eureka的高可用性" class="headerlink" title="2.4 Eureka的高可用性"></a>2.4 Eureka的高可用性</h3><blockquote>
<p>如果程序正在运行，突然Eureka宕机了</p>
<p>1、如果调用方访问过一次被调用方，Eureka的宕机就不会影响到功能</p>
<p>2、如果调用方没有访问过被调用方，Eureka的宕机就会造成当前功能的不可用到功能</p>
</blockquote>
<blockquote>
<p>搭建Eureka高可用</p>
</blockquote>
<p><img src="/posts/java/springcloud/1/images/image-20201111110217411.png" alt="image-20201111110217411"></p>
<blockquote>
<p>1、准备多态Eureka</p>
<p>采用了复制的方式，删除iml和target文件，并且修改pom.xml中的项目名称，再给负公差添加module</p>
</blockquote>
<blockquote>
<p>2、让服务注册到多台Eureka上</p>
</blockquote>
<figure class="highlight yml"><table><tr><td class="code"><pre><span class="line"><span class="attr">server:</span></span><br><span class="line">  <span class="attr">port:</span> <span class="number">8761</span></span><br><span class="line"></span><br><span class="line"><span class="attr">eureka:</span></span><br><span class="line">  <span class="attr">client:</span></span><br><span class="line">    <span class="attr">serviceUrl:</span></span><br><span class="line">      <span class="attr">defaultZone:</span> <span class="string">http://root:root@localhost:8762/eureka/</span></span><br></pre></td></tr></table></figure>

<figure class="highlight yml"><table><tr><td class="code"><pre><span class="line"><span class="attr">server:</span></span><br><span class="line">  <span class="attr">port:</span> <span class="number">8762</span></span><br><span class="line"></span><br><span class="line"><span class="attr">eureka:</span></span><br><span class="line">  <span class="attr">client:</span></span><br><span class="line">    <span class="attr">serviceUrl:</span></span><br><span class="line">      <span class="attr">defaultZone:</span> <span class="string">http://root:root@localhost:8761/eureka/</span></span><br><span class="line"></span><br></pre></td></tr></table></figure>

<blockquote>
<p>3、让多台Eureka之间相互通讯</p>
</blockquote>
<figure class="highlight yml"><table><tr><td class="code"><pre><span class="line"><span class="attr">eureka:</span></span><br><span class="line">  <span class="attr">client:</span></span><br><span class="line">    <span class="comment">#当前的eureka是单机版的 false单机版  true集群</span></span><br><span class="line">    <span class="attr">registerWithEureka:</span> <span class="literal">true</span></span><br><span class="line">    <span class="attr">fetchRegistry:</span> <span class="literal">true</span></span><br><span class="line">    <span class="attr">serviceUrl:</span></span><br><span class="line">      <span class="attr">defaultZone:</span> <span class="string">http://root:root@localhost:8761/eureka/</span></span><br></pre></td></tr></table></figure>

<h3 id="2-5-Eureka的细节"><a href="#2-5-Eureka的细节" class="headerlink" title="2.5 Eureka的细节"></a>2.5 Eureka的细节</h3><blockquote>
<p>1、EurekaClient启动时，讲自己的信息注册到EurekaServer上，EurekaServer就会储存EurekaClient的注册信息。</p>
</blockquote>
<blockquote>
<p>2、当EurekaClient调用服务时，本地没有注册信息的缓存时，去EurekaServer中获取注册信息</p>
</blockquote>
<blockquote>
<p>3、EurekaClient会通过心跳的方式去和EurekaServer进行连接。（默认30s EurekaClient就会发送一次心跳请求，如果超过了90s还没有发送心跳信息的话，EurekaSevrer就认为你宕机了，将当前的EurekaClient从注册表中移除）</p>
</blockquote>
<figure class="highlight yml"><table><tr><td class="code"><pre><span class="line"><span class="attr">eureka:</span></span><br><span class="line">  <span class="attr">instance:</span></span><br><span class="line">    <span class="attr">lease-renewal-interval-in-seconds:</span> <span class="number">30</span> <span class="comment">#心跳间隔</span></span><br><span class="line">    <span class="attr">lease-expiration-duration-in-seconds:</span> <span class="number">90</span> <span class="comment">#多久没法送，就认为你宕机了</span></span><br></pre></td></tr></table></figure>

<blockquote>
<p>4、EurekaClient会每个30s去EurekaServer中去更新本地的注册表</p>
</blockquote>
<figure class="highlight yml"><table><tr><td class="code"><pre><span class="line"><span class="attr">eureka:</span></span><br><span class="line">  <span class="attr">client:</span></span><br><span class="line">   <span class="comment">#每隔多久去更新一下本地的注册表缓存信息</span></span><br><span class="line">    <span class="attr">registry-fetch-interval-seconds:</span> <span class="number">30</span></span><br></pre></td></tr></table></figure>

<blockquote>
<p>5、Eureka的自我保护机制，统计15分钟内，如果一个服务的心跳发送比例低于85%，EurekaServer就会开启自我保护机制</p>
<p>​ 1、不会从EurekaServer中去移除长时间没有收到心跳的服务</p>
<p>​ 2、EurekaServer还是可以正常提供服务的</p>
<p>​ 3、网络稳定时，EurekaServer才会开始将自己的信息被其他节点同步过去</p>
</blockquote>
<p><img src="/posts/java/springcloud/1/images/image-20201111132523595.png" alt="image-20201111132523595"></p>
<figure class="highlight yml"><table><tr><td class="code"><pre><span class="line"><span class="attr">eureka:</span></span><br><span class="line">  <span class="comment"># Eureka保护机制配置</span></span><br><span class="line">  <span class="attr">server:</span></span><br><span class="line">   <span class="comment">#true 开启  false关闭</span></span><br><span class="line">    <span class="attr">enable-self-preservation:</span> <span class="literal">true</span></span><br></pre></td></tr></table></figure>

<blockquote>
<p>6、CAP定理，C-一致性  A-可用性  P-分区容错性，这三个特新在分布是环境下，只能满足2个，而且分区容错性在分布式环境下，时必须要满足的。只能在AC之间进行权衡。</p>
<p>1、如果选择CP，保证了一致性，可能会造成你系统在一定时间内是不可以的，如果你同步数据的时间比较长，造成的损失就越大。</p>
<p>2、如果选择AP的效果，高可用的集群，Eureka集群是无中心，Eureka即便宕机几个也不会影响系统的使用，不需要重新去枚举一个master，也会导致一定时间内数据是不一致。</p>
</blockquote>
<h2 id="三、服务间的负载均衡-Robbin"><a href="#三、服务间的负载均衡-Robbin" class="headerlink" title="三、服务间的负载均衡-Robbin"></a>三、服务间的负载均衡-Robbin</h2><h3 id="3-1-引言"><a href="#3-1-引言" class="headerlink" title="3.1 引言"></a>3.1 引言</h3><blockquote>
<p>Robbin是帮助我们实现服务和服务负载均衡</p>
<p>客户端负载均衡：customer客户端模块，将2个Search模块信息全部拉取到本地的缓存，在customer中自己做一个负载均衡的策略，选中某一个服务。</p>
<p>服务端负载均衡：在注册中心中，直接根据你指定的负载均衡策略，帮你选中一个指定的服务器信息，并返回。</p>
</blockquote>
<p><img src="/posts/java/springcloud/1/images/image-20201111134022333.png" alt="image-20201111134022333"></p>
<h3 id="3-2-Robbin的快速入门"><a href="#3-2-Robbin的快速入门" class="headerlink" title="3.2 Robbin的快速入门"></a>3.2 Robbin的快速入门</h3><blockquote>
<p>1、启动两个Search模块</p>
</blockquote>
<blockquote>
<p>2、在customer导入robbin依赖</p>
</blockquote>
<figure class="highlight xml"><table><tr><td class="code"><pre><span class="line"><span class="tag">&lt;<span class="name">dependency</span>&gt;</span></span><br><span class="line">    <span class="tag">&lt;<span class="name">groupId</span>&gt;</span>org.springframework.cloud<span class="tag">&lt;/<span class="name">groupId</span>&gt;</span></span><br><span class="line">    <span class="tag">&lt;<span class="name">artifactId</span>&gt;</span>spring-cloud-starter-netflix-ribbon<span class="tag">&lt;/<span class="name">artifactId</span>&gt;</span></span><br><span class="line"><span class="tag">&lt;/<span class="name">dependency</span>&gt;</span></span><br></pre></td></tr></table></figure>

<blockquote>
<p>3、配置整合RestTemplate和Robbin</p>
</blockquote>
<figure class="highlight java"><table><tr><td class="code"><pre><span class="line"><span class="meta">@Configuration</span></span><br><span class="line"><span class="keyword">public</span> <span class="class"><span class="keyword">class</span> <span class="title">RestTemplateConfig</span> </span>&#123;</span><br><span class="line"></span><br><span class="line">    <span class="meta">@Bean</span></span><br><span class="line">    <span class="meta">@LoadBalanced</span></span><br><span class="line">    <span class="function"><span class="keyword">public</span>   RestTemplate <span class="title">restTemplate</span><span class="params">()</span> </span>&#123;</span><br><span class="line">        <span class="keyword">return</span> <span class="keyword">new</span> RestTemplate();</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>

<blockquote>
<p>4、在customer中去访问Search</p>
</blockquote>
<figure class="highlight java"><table><tr><td class="code"><pre><span class="line"><span class="meta">@GetMapping(&quot;/customer&quot;)</span></span><br><span class="line"><span class="function"><span class="keyword">public</span> String <span class="title">customer</span><span class="params">()</span> </span>&#123;</span><br><span class="line">    String result = restTemplate.getForObject(<span class="string">&quot;http://SEARCH/search&quot;</span>, String.class);</span><br><span class="line">    <span class="comment">//4. 返回</span></span><br><span class="line">    <span class="keyword">return</span> result;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>

<h3 id="3-3-Robbin配置负载均衡策略"><a href="#3-3-Robbin配置负载均衡策略" class="headerlink" title="3.3 Robbin配置负载均衡策略"></a>3.3 Robbin配置负载均衡策略</h3><blockquote>
<p>1、负载均衡策略</p>
<ol>
<li>RandomRule：随机策略</li>
<li>RoundRobbinRule：轮询策略</li>
<li>WeightedResponseTimeRule：默认会采用轮询的策略，后续会根据服务的响应时间，自动给你分配权重</li>
<li>BestAvailableRule：根据被调用方并发数最小的去分配</li>
</ol>
</blockquote>
<blockquote>
<p>2、采用注解的形式</p>
</blockquote>
<figure class="highlight java"><table><tr><td class="code"><pre><span class="line"><span class="meta">@Bean</span></span><br><span class="line"><span class="function"><span class="keyword">public</span> IRule <span class="title">robbinRule</span><span class="params">()</span> </span>&#123;</span><br><span class="line">    <span class="keyword">return</span> <span class="keyword">new</span> RandomRule();</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>

<blockquote>
<p>3、配置文件去指定负载均衡的策略（推荐）</p>
</blockquote>
<figure class="highlight yml"><table><tr><td class="code"><pre><span class="line"><span class="comment">#指定具体服务的负载均衡策略</span></span><br><span class="line"><span class="attr">SEARCH:</span>        <span class="comment">#编写服务名称</span></span><br><span class="line">  <span class="attr">ribbon:</span></span><br><span class="line">    <span class="attr">NFLoadBalancerRuleClassName:</span> <span class="string">com.netflix.loadbalancer.WeightedResponseTimeRule</span>  <span class="comment">#具体负载均衡使用的类</span></span><br></pre></td></tr></table></figure>

<h2 id="四、服务间的调用-Feign"><a href="#四、服务间的调用-Feign" class="headerlink" title="四、服务间的调用-Feign"></a>四、服务间的调用-Feign</h2><h3 id="4-1-引言"><a href="#4-1-引言" class="headerlink" title="4.1 引言"></a>4.1 引言</h3><blockquote>
<p>Feign可以帮助我们实现面向接口编程，就直接调用其他服务，简化开发。</p>
</blockquote>
<h3 id="4-2-Feign的快速入门"><a href="#4-2-Feign的快速入门" class="headerlink" title="4.2 Feign的快速入门"></a>4.2 Feign的快速入门</h3><blockquote>
<p>1、导入依赖</p>
</blockquote>
<figure class="highlight xml"><table><tr><td class="code"><pre><span class="line"><span class="tag">&lt;<span class="name">dependency</span>&gt;</span></span><br><span class="line">    <span class="tag">&lt;<span class="name">groupId</span>&gt;</span>org.springframework.cloud<span class="tag">&lt;/<span class="name">groupId</span>&gt;</span></span><br><span class="line">    <span class="tag">&lt;<span class="name">artifactId</span>&gt;</span>spring-cloud-starter-openfeign<span class="tag">&lt;/<span class="name">artifactId</span>&gt;</span></span><br><span class="line"><span class="tag">&lt;/<span class="name">dependency</span>&gt;</span></span><br></pre></td></tr></table></figure>

<blockquote>
<p>2、添加一个注解<code>@EnableFeignClients</code></p>
</blockquote>
<figure class="highlight java"><table><tr><td class="code"><pre><span class="line"><span class="meta">@EnableEurekaClient</span></span><br><span class="line"><span class="meta">@SpringBootApplication</span></span><br><span class="line"><span class="meta">@EnableFeignClients</span></span><br><span class="line"><span class="keyword">public</span> <span class="class"><span class="keyword">class</span> <span class="title">CustomerApplication</span> </span>&#123;</span><br><span class="line">    <span class="function"><span class="keyword">public</span> <span class="keyword">static</span> <span class="keyword">void</span> <span class="title">main</span><span class="params">(String[] args)</span> </span>&#123;</span><br><span class="line">        SpringApplication.run(CustomerApplication.class,args);</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>

<blockquote>
<p>3、创建一个接口，并且和search模块做映射</p>
</blockquote>
<figure class="highlight java"><table><tr><td class="code"><pre><span class="line"><span class="comment">//指定服务名称</span></span><br><span class="line"><span class="meta">@FeignClient(&quot;SEARCH&quot;)</span></span><br><span class="line"><span class="keyword">public</span> <span class="class"><span class="keyword">interface</span> <span class="title">SearchClient</span> </span>&#123;</span><br><span class="line"></span><br><span class="line">    <span class="comment">//value -&gt; 目标服务的请求路径，method -&gt; 映射请求方式</span></span><br><span class="line">    <span class="meta">@RequestMapping(value = &quot;/search&quot;,method = RequestMethod.GET)</span></span><br><span class="line">    <span class="function"><span class="keyword">public</span> String <span class="title">search</span><span class="params">()</span></span>;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>

<blockquote>
<p>4、测试使用</p>
</blockquote>
<figure class="highlight java"><table><tr><td class="code"><pre><span class="line"><span class="meta">@Autowired</span></span><br><span class="line"><span class="keyword">private</span> SearchClient searchClient;</span><br><span class="line"></span><br><span class="line"><span class="meta">@GetMapping(&quot;/customer&quot;)</span></span><br><span class="line"><span class="function"><span class="keyword">public</span> String <span class="title">customer</span><span class="params">()</span> </span>&#123;</span><br><span class="line">    String result = searchClient.search();</span><br><span class="line">    <span class="keyword">return</span> result;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>

<h3 id="4-3-Feign的传递参数方式"><a href="#4-3-Feign的传递参数方式" class="headerlink" title="4.3 Feign的传递参数方式"></a>4.3 Feign的传递参数方式</h3><blockquote>
<p>1、注意事项</p>
<ol>
<li>如果你传递的参数，比较复杂时，默认会采用POST的请求方式。</li>
<li>传递单个参数时，推荐使用@PathVariable，如果传递的单个参数比较多，这里也可以采用@RequestParam，不要省略value属性</li>
<li>传递对象信息时，统一采用json的方式，添加@RequestBody</li>
<li>Client接口必须采用@RequestMapping</li>
</ol>
</blockquote>
<blockquote>
<p>2、在Search模块下准备三个接口</p>
</blockquote>
<figure class="highlight java"><table><tr><td class="code"><pre><span class="line"><span class="meta">@GetMapping(&quot;/search/&#123;id&#125;&quot;)</span></span><br><span class="line"><span class="function"><span class="keyword">public</span> Customer <span class="title">findById</span><span class="params">(<span class="meta">@PathVariable</span> Integer id)</span> </span>&#123;</span><br><span class="line">    <span class="keyword">return</span> <span class="keyword">new</span> Customer(<span class="number">1</span>, <span class="string">&quot;zhangsan&quot;</span>, <span class="number">23</span>);</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="meta">@GetMapping(&quot;/getCustomer&quot;)</span></span><br><span class="line"><span class="function"><span class="keyword">public</span> Customer <span class="title">getcustomer</span><span class="params">(<span class="meta">@RequestParam</span> Integer id, <span class="meta">@RequestParam</span> String name)</span> </span>&#123;</span><br><span class="line">    <span class="keyword">return</span> <span class="keyword">new</span> Customer(id, name, <span class="number">23</span>);</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="meta">@PostMapping(&quot;save&quot;)</span></span><br><span class="line"><span class="function"><span class="keyword">public</span> Customer <span class="title">save</span><span class="params">(<span class="meta">@RequestBody</span> Customer customer)</span> </span>&#123;</span><br><span class="line">    <span class="keyword">return</span> customer;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>

<blockquote>
<p>3、封装Customer模块的Controller</p>
</blockquote>
<figure class="highlight java"><table><tr><td class="code"><pre><span class="line"><span class="meta">@GetMapping(&quot;/customer/&#123;id&#125;&quot;)</span></span><br><span class="line"><span class="function"><span class="keyword">public</span> Customer <span class="title">findById</span><span class="params">(<span class="meta">@PathVariable</span> Integer id)</span> </span>&#123;</span><br><span class="line">    <span class="keyword">return</span> searchClient.findById(id);</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="meta">@GetMapping(&quot;/getCustomer&quot;)</span></span><br><span class="line"><span class="function"><span class="keyword">public</span> Customer <span class="title">getcustomer</span><span class="params">(<span class="meta">@RequestParam</span> Integer id, <span class="meta">@RequestParam</span> String name)</span> </span>&#123;</span><br><span class="line">    <span class="keyword">return</span> searchClient.getcustomer(id,name);</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="meta">@GetMapping(&quot;save&quot;)</span></span><br><span class="line"><span class="function"><span class="keyword">public</span> Customer <span class="title">save</span><span class="params">(Customer customer)</span> </span>&#123;</span><br><span class="line">    <span class="keyword">return</span> searchClient.save(customer);</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>

<blockquote>
<p>4、再封装Client接口</p>
</blockquote>
<figure class="highlight java"><table><tr><td class="code"><pre><span class="line"><span class="meta">@RequestMapping(value = &quot;/search/&#123;id&#125;&quot;,method = RequestMethod.GET)</span></span><br><span class="line"><span class="function">Customer <span class="title">findById</span><span class="params">(<span class="meta">@PathVariable(value = &quot;id&quot;)</span> Integer id)</span></span>;</span><br><span class="line"></span><br><span class="line"><span class="meta">@RequestMapping(value = &quot;/getCustomer&quot;,method = RequestMethod.GET)</span></span><br><span class="line"><span class="function">Customer <span class="title">getcustomer</span><span class="params">(<span class="meta">@RequestParam(value = &quot;id&quot;)</span> Integer id, <span class="meta">@RequestParam(value = &quot;name&quot;)</span> String name)</span></span>;</span><br><span class="line"></span><br><span class="line"><span class="meta">@RequestMapping(value = &quot;save&quot;,method = RequestMethod.GET)</span> <span class="comment">//会自动转化成POST请求  405</span></span><br><span class="line"><span class="function">Customer <span class="title">save</span><span class="params">(<span class="meta">@RequestBody</span> Customer customer)</span></span>;</span><br></pre></td></tr></table></figure>

<blockquote>
<p>5、测试</p>
</blockquote>
<p><img src="/posts/java/springcloud/1/images/image-20201111155409030.png" alt="image-20201111155409030"></p>
<h3 id="4-4-Feign的Fallback"><a href="#4-4-Feign的Fallback" class="headerlink" title="4.4 Feign的Fallback"></a>4.4 Feign的Fallback</h3><blockquote>
<p>Fallback可以帮助我们在使用Feign去调用另一个服务时，如果出现了问题，走服务降级，返回一个错误的数据，避免功能因为一个服务出现问题，全部失效</p>
</blockquote>
<blockquote>
<p>1、创建一个POJO类，实现Client接口</p>
</blockquote>
<figure class="highlight java"><table><tr><td class="code"><pre><span class="line"><span class="meta">@Component</span></span><br><span class="line"><span class="keyword">public</span> <span class="class"><span class="keyword">class</span> <span class="title">SearchClientFallBack</span> <span class="keyword">implements</span> <span class="title">SearchClient</span> </span>&#123;</span><br><span class="line">    <span class="meta">@Override</span></span><br><span class="line">    <span class="function"><span class="keyword">public</span> String <span class="title">search</span><span class="params">()</span> </span>&#123;</span><br><span class="line">        <span class="keyword">return</span> <span class="string">&quot;出现问题了&quot;</span>;</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="meta">@Override</span></span><br><span class="line">    <span class="function"><span class="keyword">public</span> Customer <span class="title">findById</span><span class="params">(Integer id)</span> </span>&#123;</span><br><span class="line">        <span class="keyword">return</span> <span class="keyword">null</span>;</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="meta">@Override</span></span><br><span class="line">    <span class="function"><span class="keyword">public</span> Customer <span class="title">getcustomer</span><span class="params">(Integer id, String name)</span> </span>&#123;</span><br><span class="line">        <span class="keyword">return</span> <span class="keyword">null</span>;</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="meta">@Override</span></span><br><span class="line">    <span class="function"><span class="keyword">public</span> Customer <span class="title">save</span><span class="params">(Customer customer)</span> </span>&#123;</span><br><span class="line">        <span class="keyword">return</span> <span class="keyword">null</span>;</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>

<blockquote>
<p>2、修改Client接口中的注解，添加一个属性</p>
</blockquote>
<figure class="highlight java"><table><tr><td class="code"><pre><span class="line"><span class="meta">@FeignClient(value = &quot;SEARCH&quot;,fallback = SearchClientFallBack.class)</span></span><br></pre></td></tr></table></figure>

<blockquote>
<p>3、添加一个配置文件。</p>
</blockquote>
<figure class="highlight yml"><table><tr><td class="code"><pre><span class="line"><span class="comment">#feign和hystrix主件整合</span></span><br><span class="line"><span class="attr">feign:</span></span><br><span class="line">  <span class="attr">hystrix:</span></span><br><span class="line">    <span class="attr">enabled:</span> <span class="literal">true</span></span><br></pre></td></tr></table></figure>

<blockquote>
<p>调用方无法知道具体的错误信息是什么，通过FallBackFactory的方式去实现这个功能</p>
</blockquote>
<blockquote>
<p>1、FallBackFactory基于fallback</p>
</blockquote>
<blockquote>
<p>2、创建一个POJO类，实现FallBackFactory<Client></p>
</blockquote>
<figure class="highlight java"><table><tr><td class="code"><pre><span class="line"><span class="meta">@Component</span></span><br><span class="line"><span class="keyword">public</span> <span class="class"><span class="keyword">class</span> <span class="title">SearchClientFallBackFactory</span> <span class="keyword">implements</span> <span class="title">FallbackFactory</span>&lt;<span class="title">SearchClient</span>&gt; </span>&#123;</span><br><span class="line"></span><br><span class="line">    <span class="meta">@Autowired</span></span><br><span class="line">    <span class="keyword">private</span> SearchClientFallBack searchClientFallBack;</span><br><span class="line">    <span class="meta">@Override</span></span><br><span class="line">    <span class="function"><span class="keyword">public</span> SearchClient <span class="title">create</span><span class="params">(Throwable throwable)</span> </span>&#123;</span><br><span class="line">        throwable.printStackTrace();</span><br><span class="line">        <span class="keyword">return</span> searchClientFallBack;</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>

<blockquote>
<p>3、修改Client接口中的属性</p>
</blockquote>
<figure class="highlight java"><table><tr><td class="code"><pre><span class="line"><span class="meta">@FeignClient(value = &quot;SEARCH&quot;,</span></span><br><span class="line"><span class="meta">        fallbackFactory = SearchClientFallBackFactory.class</span></span><br><span class="line"><span class="meta">)</span></span><br></pre></td></tr></table></figure>

<h2 id="五、服务的隔离及熔断器-Hystrix"><a href="#五、服务的隔离及熔断器-Hystrix" class="headerlink" title="五、服务的隔离及熔断器-Hystrix"></a>五、服务的隔离及熔断器-Hystrix</h2><h3 id="5-1-引言"><a href="#5-1-引言" class="headerlink" title="5.1 引言"></a>5.1 引言</h3><p><img src="/posts/java/springcloud/1/images/image-20201111162630381.png" alt="image-20201111162630381"></p>
<h3 id="5-2-降级机制实现"><a href="#5-2-降级机制实现" class="headerlink" title="5.2 降级机制实现"></a>5.2 降级机制实现</h3><blockquote>
<p>1、导入依赖</p>
</blockquote>
<figure class="highlight xml"><table><tr><td class="code"><pre><span class="line"><span class="tag">&lt;<span class="name">dependency</span>&gt;</span></span><br><span class="line">    <span class="tag">&lt;<span class="name">groupId</span>&gt;</span>org.springframework.cloud<span class="tag">&lt;/<span class="name">groupId</span>&gt;</span></span><br><span class="line">    <span class="tag">&lt;<span class="name">artifactId</span>&gt;</span>spring-cloud-starter-netflix-hystrix<span class="tag">&lt;/<span class="name">artifactId</span>&gt;</span></span><br><span class="line"><span class="tag">&lt;/<span class="name">dependency</span>&gt;</span></span><br></pre></td></tr></table></figure>

<blockquote>
<p>2、添加一个注解<code>@EnableCircuitBreaker</code></p>
</blockquote>
<figure class="highlight java"><table><tr><td class="code"><pre><span class="line"><span class="meta">@EnableEurekaClient</span></span><br><span class="line"><span class="meta">@SpringBootApplication</span></span><br><span class="line"><span class="meta">@EnableCircuitBreaker</span></span><br><span class="line"><span class="keyword">public</span> <span class="class"><span class="keyword">class</span> <span class="title">CustomerApplication</span> </span>&#123;</span><br><span class="line">    <span class="function"><span class="keyword">public</span> <span class="keyword">static</span> <span class="keyword">void</span> <span class="title">main</span><span class="params">(String[] args)</span> </span>&#123;</span><br><span class="line">        SpringApplication.run(CustomerApplication.class,args);</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>

<blockquote>
<p>3、针对某一个接口去编写他的降级方法</p>
</blockquote>
<figure class="highlight java"><table><tr><td class="code"><pre><span class="line"><span class="meta">@GetMapping(&quot;/customer/&#123;id&#125;&quot;)</span></span><br><span class="line"><span class="meta">@HystrixCommand(fallbackMethod =&quot;findByIdFallBack&quot; )</span></span><br><span class="line"><span class="function"><span class="keyword">public</span> Customer <span class="title">findById</span><span class="params">(<span class="meta">@PathVariable</span> Integer id)</span> </span>&#123;</span><br><span class="line">    <span class="keyword">int</span> i = <span class="number">1</span>/<span class="number">0</span>;</span><br><span class="line">    <span class="keyword">return</span> searchClient.findById(id);</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="comment">//findById的降级方法，方法描述要与接口一致</span></span><br><span class="line"><span class="function"><span class="keyword">public</span> Customer <span class="title">findByIdFallBack</span><span class="params">(Integer id)</span> </span>&#123;</span><br><span class="line">    <span class="keyword">return</span> <span class="keyword">new</span> Customer(-<span class="number">1</span>,<span class="string">&quot;&quot;</span>,<span class="number">0</span>);</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>

<blockquote>
<p>4、在接口上添加注解</p>
</blockquote>
<figure class="highlight java"><table><tr><td class="code"><pre><span class="line"><span class="meta">@HystrixCommand(fallbackMethod =&quot;findByIdFallBack&quot; )</span></span><br></pre></td></tr></table></figure>

<blockquote>
<p>5、测试</p>
</blockquote>
<p><img src="/posts/java/springcloud/1/images/image-20201111164239591.png" alt="image-20201111164239591"></p>
<h3 id="5-3-线程隔离"><a href="#5-3-线程隔离" class="headerlink" title="5.3 线程隔离"></a>5.3 线程隔离</h3><blockquote>
<p>如果使用Tomcat的线程池去接收用户的请求，使用当前线程去执行其他服务的功能，如果某一个服务出现了故障，导致tomcat的线程大量的堆积，导致tomcat无法处理其他业务功能。</p>
<p>1、Hystrix线程池（默认），接收用户请求采用tomcat的线程池，执行业务代码，调用其他服务时，采用Hystrix的线程池。</p>
<p>2、信号量，使用的还是Tomcat的线程池，帮助我们取关了Tomcat的线程池</p>
</blockquote>
<blockquote>
<p>1、Hystrix的线程池的配置(具体的配置属性需要去查看HystrixCommandProperties类)  <a target="_blank" rel="noopener" href="https://github.com/Netflix/Hystrix/wiki/Configuration">wiki</a></p>
<ol>
<li>线程隔离策略：name = <code>hystrix.command.default.execution.isolation.strategy</code>,value=<code>THREAD</code>,<code>SEMAPHORE</code></li>
<li>指定超时时间（针对线程池）：name= <code>hystrix.command.default.execution.isolation.thread.timeoutInMilliseconds</code> ,value =<code>1000</code></li>
<li>是否开启超时时间配置：name=<code>hystrix.command.default.execution.timeout.enabled</code>,value=<code>true</code></li>
<li>超时之后是否中断线程：name=<code>hystrix.command.default.execution.isolation.thread.interruptOnTimeout</code>,value=<code>true</code></li>
<li>取消任务之后是否中断线程：name=<code>hystrix.command.default.execution.isolation.thread.interruptOnCancel</code>,value=false</li>
</ol>
</blockquote>
<blockquote>
<p>2、信号量配置信息</p>
<ol>
<li>线程隔离策略：name = <code>hystrix.command.default.execution.isolation.strategy</code>,value=<code>THREAD</code>,<code>SEMAPHORE</code></li>
<li>指定信号量的最大并发请求数：name=<code>hystrix.command.default.execution.isolation.semaphore.maxConcurrentRequests</code>,value=<code>10</code></li>
</ol>
</blockquote>
<h3 id="5-4-断路器"><a href="#5-4-断路器" class="headerlink" title="5.4 断路器"></a>5.4 断路器</h3><h4 id="5-4-1-断路器介绍"><a href="#5-4-1-断路器介绍" class="headerlink" title="5.4.1 断路器介绍"></a>5.4.1 断路器介绍</h4><blockquote>
<p>如果调用指定服务时，如果说这个服务的失败率达到你输入的阈值麻将断路器从closed状态，转变为open状态，指定服务时无法被访问的，如果你访问就直接走fallback方法，在一定时间内，open状态会再次转变为half open状态，允许一个请求发送到我指定服务，如果成功，则转变为closed，如果失败，服务再次转变为open状态，会再次循环到hald open，直到专路器回到一个closed状态。</p>
</blockquote>
<p><img src="/posts/java/springcloud/1/images/image-20201111181650929.png" alt="image-20201111181650929"></p>
<h4 id="5-4-2-配置断路器的监控界面"><a href="#5-4-2-配置断路器的监控界面" class="headerlink" title="5.4.2 配置断路器的监控界面"></a>5.4.2 配置断路器的监控界面</h4><blockquote>
<p>1、导入依赖</p>
</blockquote>
<figure class="highlight xml"><table><tr><td class="code"><pre><span class="line"><span class="tag">&lt;<span class="name">dependency</span>&gt;</span></span><br><span class="line">    <span class="tag">&lt;<span class="name">groupId</span>&gt;</span>org.springframework.cloud<span class="tag">&lt;/<span class="name">groupId</span>&gt;</span></span><br><span class="line">    <span class="tag">&lt;<span class="name">artifactId</span>&gt;</span>spring-cloud-starter-netflix-hystrix-dashboard<span class="tag">&lt;/<span class="name">artifactId</span>&gt;</span></span><br><span class="line"><span class="tag">&lt;/<span class="name">dependency</span>&gt;</span></span><br></pre></td></tr></table></figure>

<blockquote>
<p>2、在启动类中添加注解<code>@EnableHystrixDashboard</code></p>
</blockquote>
<figure class="highlight java"><table><tr><td class="code"><pre><span class="line"><span class="meta">@EnableEurekaClient</span></span><br><span class="line"><span class="meta">@SpringBootApplication</span></span><br><span class="line"><span class="meta">@EnableFeignClients</span></span><br><span class="line"><span class="meta">@EnableCircuitBreaker</span></span><br><span class="line"><span class="meta">@EnableHystrixDashboard</span></span><br><span class="line"><span class="meta">@ServletComponentScan(&quot;cn.zyjblogs.servlet&quot;)</span></span><br><span class="line"><span class="keyword">public</span> <span class="class"><span class="keyword">class</span> <span class="title">CustomerApplication</span> </span>&#123;</span><br><span class="line">    <span class="function"><span class="keyword">public</span> <span class="keyword">static</span> <span class="keyword">void</span> <span class="title">main</span><span class="params">(String[] args)</span> </span>&#123;</span><br><span class="line">        SpringApplication.run(CustomerApplication.class,args);</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>

<blockquote>
<p>3、配置一个Servlet路径，指定上Hystrix的Servlet</p>
</blockquote>
<figure class="highlight java"><table><tr><td class="code"><pre><span class="line"><span class="meta">@WebServlet(&quot;/hystrix.stream&quot;)</span></span><br><span class="line"><span class="keyword">public</span> <span class="class"><span class="keyword">class</span> <span class="title">HystrixServlet</span> <span class="keyword">extends</span> <span class="title">HystrixMetricsStreamServlet</span> </span>&#123;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>

<blockquote>
<p>4、在启动类上添加扫描Servlet的注解<code>@ServletComponentScan(&quot;cn.zyjblogs.servlet&quot;)</code></p>
</blockquote>
<blockquote>
<p>5、配置文件</p>
</blockquote>
<figure class="highlight yml"><table><tr><td class="code"><pre><span class="line"><span class="attr">hystrix:</span></span><br><span class="line">  <span class="attr">dashboard:</span></span><br><span class="line">    <span class="attr">proxy-stream-allow-list:</span> <span class="string">localhost</span></span><br></pre></td></tr></table></figure>

<blockquote>
<p>6、测试</p>
</blockquote>
<p>直接访问: <a href="http://host:port/hystrix.stream">http://host:port/hystrix.stream</a></p>
<p><img src="/posts/java/springcloud/1/images/1605103421256.png" alt="1605103421256"></p>
<blockquote>
<p>在当前位置输入映射好的servlet路径</p>
</blockquote>
<p><img src="/posts/java/springcloud/1/images/1605103436874.png" alt="1605103436874"></p>
<h4 id="5-4-3-配置断路器的属性"><a href="#5-4-3-配置断路器的属性" class="headerlink" title="5.4.3 配置断路器的属性"></a>5.4.3 配置断路器的属性</h4><blockquote>
<p>断路器的属性(10秒之内)</p>
<ol>
<li>断路器的开关：name=<code>hystrix.command.default.circuitBreaker.enabled</code>,value=<code>true</code></li>
<li>失败阈值的总请求数：name=<code>hystrix.command.default.circuitBreaker.requestVolumeThreshold</code>,value=<code>20</code></li>
<li>请求总数失败率达到%多少时打开断路器：name=<code>hystrix.command.default.circuitBreaker.errorThresholdPercentage</code>,value=<code>50</code></li>
<li>断路器open状态后，多少秒是拒绝请求的：name=<code>hystrix.command.default.circuitBreaker.sleepWindowInMilliseconds</code>value=<code>5000</code></li>
<li>强制让服务拒绝请求：name=<code>hystrix.command.default.circuitBreaker.forceOpen</code>,value=<code>false</code></li>
<li>强制让服务接收请求：name=<code>hystrix.command.default.circuitBreaker.forceClosed</code>,value=<code>false</code></li>
</ol>
</blockquote>
<blockquote>
<p>具体配置方式</p>
</blockquote>
<figure class="highlight java"><table><tr><td class="code"><pre><span class="line"><span class="meta">@GetMapping(&quot;/customer/&#123;id&#125;&quot;)</span></span><br><span class="line"><span class="meta">@HystrixCommand(fallbackMethod =&quot;findByIdFallBack&quot;,commandProperties = &#123;</span></span><br><span class="line"><span class="meta">    @HystrixProperty(name = &quot;circuitBreaker.enabled&quot;,value=&quot;true&quot;),</span></span><br><span class="line"><span class="meta">    @HystrixProperty(name = &quot;circuitBreaker.requestVolumeThreshold&quot;,value=&quot;10&quot;),</span></span><br><span class="line"><span class="meta">    @HystrixProperty(name = &quot;circuitBreaker.errorThresholdPercentage&quot;,value=&quot;70&quot;),</span></span><br><span class="line"><span class="meta">    @HystrixProperty(name = &quot;circuitBreaker.sleepWindowInMilliseconds&quot;,value=&quot;5000&quot;)</span></span><br><span class="line"><span class="meta">&#125;)</span></span><br></pre></td></tr></table></figure>

<h3 id="5-5-请求缓存"><a href="#5-5-请求缓存" class="headerlink" title="5.5 请求缓存"></a>5.5 请求缓存</h3><h4 id="5-5-1-请求缓存的介绍"><a href="#5-5-1-请求缓存的介绍" class="headerlink" title="5.5.1 请求缓存的介绍"></a>5.5.1 请求缓存的介绍</h4><blockquote>
<p>1、请求缓存的声明周期是一次请求</p>
<p>2、请求缓存是缓存当前线程中的一个方法，将方法参数作为key，方法的返回结果作为value</p>
<p>3、在一次请求中，目标方法被调用过一次以后就都会被缓存</p>
</blockquote>
<p><img src="/posts/java/springcloud/1/images/1605104987931.png" alt="1605104987931"></p>
<h4 id="5-5-2-请求缓存的实现"><a href="#5-5-2-请求缓存的实现" class="headerlink" title="5.5.2 请求缓存的实现"></a>5.5.2 请求缓存的实现</h4><blockquote>
<p>1、创建一个Service，在Service中调用Search服务</p>
</blockquote>
<figure class="highlight java"><table><tr><td class="code"><pre><span class="line"><span class="meta">@Service</span></span><br><span class="line"><span class="keyword">public</span> <span class="class"><span class="keyword">class</span> <span class="title">CustomerService</span> </span>&#123;</span><br><span class="line"></span><br><span class="line">    <span class="meta">@Autowired</span></span><br><span class="line">    <span class="keyword">private</span> SearchClient searchClient;</span><br><span class="line"></span><br><span class="line">    <span class="meta">@CacheResult</span></span><br><span class="line">    <span class="meta">@HystrixCommand(commandKey = &quot;findById&quot;)</span></span><br><span class="line">    <span class="function"><span class="keyword">public</span> Customer <span class="title">findById</span><span class="params">(<span class="meta">@CacheKey</span> Integer id)</span> <span class="keyword">throws</span> InterruptedException </span>&#123;</span><br><span class="line">        <span class="keyword">return</span> searchClient.findById(id);</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="meta">@CacheRemove(commandKey = &quot;findById&quot;)</span></span><br><span class="line">    <span class="meta">@HystrixCommand</span></span><br><span class="line">    <span class="function"><span class="keyword">public</span> <span class="keyword">void</span> <span class="title">clearFindById</span><span class="params">(<span class="meta">@CacheKey</span> Integer id)</span> </span>&#123;</span><br><span class="line">        System.out.println(<span class="string">&quot;findById缓存被清空&quot;</span>);</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>

<blockquote>
<p>2、使用请求缓存的注解<code>@CacheResult</code> <code>CacheRemove</code></p>
<ol>
<li>@CacheResult：帮助我们缓存当前方法的返回结果（必须配合@HystrixCommand使用）</li>
<li>@CacheRemove：帮助我们清除某一个缓存信息（基于commandKey）</li>
<li>@CacheKey：指定那个方法参数作为缓存标识</li>
</ol>
</blockquote>
<blockquote>
<p>3、修改Search模块的结果返回值</p>
</blockquote>
<figure class="highlight java"><table><tr><td class="code"><pre><span class="line"><span class="keyword">return</span> <span class="keyword">new</span> Customer(id, name, (<span class="keyword">int</span>) (Math.random() * <span class="number">100000</span>));</span><br></pre></td></tr></table></figure>

<blockquote>
<p>4、编写Filter，去构建HystrixRequestContext</p>
</blockquote>
<figure class="highlight java"><table><tr><td class="code"><pre><span class="line"><span class="meta">@WebFilter(&quot;/*&quot;)</span></span><br><span class="line"><span class="keyword">public</span> <span class="class"><span class="keyword">class</span> <span class="title">HystrixRequestContextFilter</span> <span class="keyword">implements</span> <span class="title">Filter</span> </span>&#123;</span><br><span class="line">    <span class="meta">@Override</span></span><br><span class="line">    <span class="function"><span class="keyword">public</span> <span class="keyword">void</span> <span class="title">doFilter</span><span class="params">(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain)</span> <span class="keyword">throws</span> IOException, ServletException </span>&#123;</span><br><span class="line">        HystrixRequestContext.initializeContext();</span><br><span class="line">        filterChain.doFilter(servletRequest,servletResponse);</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>

<blockquote>
<p>5、修改Controller</p>
</blockquote>
<figure class="highlight java"><table><tr><td class="code"><pre><span class="line"><span class="meta">@Autowired</span></span><br><span class="line"><span class="keyword">private</span> CustomerService customerService;</span><br><span class="line"></span><br><span class="line"> <span class="meta">@GetMapping(&quot;/customer/&#123;id&#125;&quot;)</span></span><br><span class="line">  <span class="meta">@HystrixCommand(</span></span><br><span class="line"><span class="meta">      fallbackMethod = &quot;findByIdFallBack&quot;,</span></span><br><span class="line"><span class="meta">      commandProperties = &#123;</span></span><br><span class="line"><span class="meta">        @HystrixProperty(name = &quot;circuitBreaker.enabled&quot;, value = &quot;true&quot;),</span></span><br><span class="line"><span class="meta">        @HystrixProperty(name = &quot;circuitBreaker.requestVolumeThreshold&quot;, value = &quot;10&quot;),</span></span><br><span class="line"><span class="meta">        @HystrixProperty(name = &quot;circuitBreaker.errorThresholdPercentage&quot;, value = &quot;70&quot;),</span></span><br><span class="line"><span class="meta">        @HystrixProperty(name = &quot;circuitBreaker.sleepWindowInMilliseconds&quot;, value = &quot;5000&quot;),</span></span><br><span class="line"><span class="meta">      &#125;)</span></span><br><span class="line">  <span class="function"><span class="keyword">public</span> Customer <span class="title">findById</span><span class="params">(<span class="meta">@PathVariable</span> Integer id)</span> <span class="keyword">throws</span> InterruptedException </span>&#123;</span><br><span class="line">    System.out.println(Thread.currentThread().getName());</span><br><span class="line">    <span class="keyword">if</span> (id == <span class="number">1</span>) &#123;</span><br><span class="line">      <span class="keyword">int</span> i = <span class="number">1</span> / <span class="number">0</span>;</span><br><span class="line">    &#125;</span><br><span class="line">    <span class="comment">//一下为添加内容</span></span><br><span class="line">    System.out.println(customerService.findById(id));</span><br><span class="line">    System.out.println(customerService.findById(id));</span><br><span class="line">    customerService.clearFindById(id);</span><br><span class="line">    System.out.println(customerService.findById(id));</span><br><span class="line">    System.out.println(customerService.findById(id));</span><br><span class="line">    customerService.clearFindById(id);</span><br><span class="line"></span><br><span class="line">    <span class="keyword">return</span> searchClient.findById(id);</span><br><span class="line">  &#125;</span><br></pre></td></tr></table></figure>

<blockquote>
<p>6、测试</p>
</blockquote>
<p><img src="/posts/java/springcloud/1/images/1605106759891.png" alt="1605106759891"></p>
<h2 id="六、服务的网关-Zuul"><a href="#六、服务的网关-Zuul" class="headerlink" title="六、服务的网关-Zuul"></a>六、服务的网关-Zuul</h2><h3 id="6-1-引言"><a href="#6-1-引言" class="headerlink" title="6.1 引言"></a>6.1 引言</h3><blockquote>
<p>1、客户端维护大量的ip和port信息，直接访问指定服务</p>
<p>2、认证和授权操作，需要在每一个模块中添加认证和授权操作</p>
<p>3、项目迭代，服务拆分，服务要合并，需要客户端镜像大量的变化</p>
<p>4、统一的把安全性校验都放在Zuul中</p>
</blockquote>
<p><img src="/posts/java/springcloud/1/images/image-20201112110708902.png" alt="网关"></p>
<h3 id="6-2-Zuul的快速入门"><a href="#6-2-Zuul的快速入门" class="headerlink" title="6.2 Zuul的快速入门"></a>6.2 Zuul的快速入门</h3><blockquote>
<p>1、创建Maven项目，修改SpringBoot</p>
</blockquote>
<blockquote>
<p>2、导入依赖</p>
</blockquote>
<figure class="highlight xml"><table><tr><td class="code"><pre><span class="line"><span class="tag">&lt;<span class="name">dependency</span>&gt;</span></span><br><span class="line">    <span class="tag">&lt;<span class="name">groupId</span>&gt;</span>org.springframework.boot<span class="tag">&lt;/<span class="name">groupId</span>&gt;</span></span><br><span class="line">    <span class="tag">&lt;<span class="name">artifactId</span>&gt;</span>spring-boot-starter-web<span class="tag">&lt;/<span class="name">artifactId</span>&gt;</span></span><br><span class="line"><span class="tag">&lt;/<span class="name">dependency</span>&gt;</span></span><br><span class="line"><span class="tag">&lt;<span class="name">dependency</span>&gt;</span></span><br><span class="line">    <span class="tag">&lt;<span class="name">groupId</span>&gt;</span>org.springframework.cloud<span class="tag">&lt;/<span class="name">groupId</span>&gt;</span></span><br><span class="line">    <span class="tag">&lt;<span class="name">artifactId</span>&gt;</span>spring-cloud-starter-netflix-zuul<span class="tag">&lt;/<span class="name">artifactId</span>&gt;</span></span><br><span class="line"><span class="tag">&lt;/<span class="name">dependency</span>&gt;</span></span><br><span class="line"><span class="tag">&lt;<span class="name">dependency</span>&gt;</span></span><br><span class="line">    <span class="tag">&lt;<span class="name">groupId</span>&gt;</span>org.springframework.cloud<span class="tag">&lt;/<span class="name">groupId</span>&gt;</span></span><br><span class="line">    <span class="tag">&lt;<span class="name">artifactId</span>&gt;</span>spring-cloud-starter-netflix-eureka-client<span class="tag">&lt;/<span class="name">artifactId</span>&gt;</span></span><br><span class="line"><span class="tag">&lt;/<span class="name">dependency</span>&gt;</span></span><br></pre></td></tr></table></figure>

<blockquote>
<p>3、添加注解<code>@EnableZuulProxy</code> <code>@EnableEurekaClient</code></p>
</blockquote>
<figure class="highlight java"><table><tr><td class="code"><pre><span class="line"><span class="meta">@SpringBootApplication</span></span><br><span class="line"><span class="meta">@EnableEurekaClient</span></span><br><span class="line"><span class="meta">@EnableZuulProxy</span></span><br><span class="line"><span class="keyword">public</span> <span class="class"><span class="keyword">class</span> <span class="title">ZuulApplication</span> </span>&#123;</span><br><span class="line">    <span class="function"><span class="keyword">public</span> <span class="keyword">static</span> <span class="keyword">void</span> <span class="title">main</span><span class="params">(String[] args)</span> </span>&#123;</span><br><span class="line">        SpringApplication.run(ZuulApplication.class,args);</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>

<blockquote>
<p>4、编写配置文件</p>
</blockquote>
<figure class="highlight yml"><table><tr><td class="code"><pre><span class="line"><span class="attr">server:</span></span><br><span class="line">  <span class="attr">port:</span> <span class="number">80</span></span><br><span class="line"><span class="comment">#指定Eureka服务地址</span></span><br><span class="line"><span class="attr">eureka:</span></span><br><span class="line">  <span class="attr">client:</span></span><br><span class="line">    <span class="attr">service-url:</span></span><br><span class="line">      <span class="attr">defaultZone:</span> <span class="string">http://root:root@localhost:8761/eureka,http://root:root@localhost:8762/eureka</span></span><br><span class="line"></span><br><span class="line"><span class="comment">#指定服务名称</span></span><br><span class="line"><span class="attr">spring:</span></span><br><span class="line">  <span class="attr">application:</span></span><br><span class="line">    <span class="attr">name:</span> <span class="string">ZUUL</span></span><br></pre></td></tr></table></figure>

<blockquote>
<p>5、测试</p>
</blockquote>
<p><img src="/posts/java/springcloud/1/images/image-20201112113609523.png" alt="image-20201112113609523"></p>
<h3 id="6-3-Zuul常用配置信息"><a href="#6-3-Zuul常用配置信息" class="headerlink" title="6.3  Zuul常用配置信息"></a>6.3  Zuul常用配置信息</h3><h4 id="6-3-1-Zuul的监控界面"><a href="#6-3-1-Zuul的监控界面" class="headerlink" title="6.3.1 Zuul的监控界面"></a>6.3.1 Zuul的监控界面</h4><blockquote>
<p>1、导入依赖</p>
</blockquote>
<figure class="highlight xml"><table><tr><td class="code"><pre><span class="line"><span class="tag">&lt;<span class="name">dependency</span>&gt;</span></span><br><span class="line">    <span class="tag">&lt;<span class="name">groupId</span>&gt;</span>org.springframework.boot<span class="tag">&lt;/<span class="name">groupId</span>&gt;</span></span><br><span class="line">    <span class="tag">&lt;<span class="name">artifactId</span>&gt;</span>spring-boot-starter-actuator<span class="tag">&lt;/<span class="name">artifactId</span>&gt;</span></span><br><span class="line"><span class="tag">&lt;/<span class="name">dependency</span>&gt;</span></span><br></pre></td></tr></table></figure>

<blockquote>
<p>2、编写配置文件</p>
</blockquote>
<figure class="highlight yml"><table><tr><td class="code"><pre><span class="line"><span class="comment">#查看zuul的监考界面（开发时，配置为*，上线，不要配置）</span></span><br><span class="line"><span class="attr">management:</span></span><br><span class="line">  <span class="attr">endpoints:</span></span><br><span class="line">    <span class="attr">web:</span></span><br><span class="line">      <span class="attr">exposure:</span></span><br><span class="line">        <span class="attr">include:</span> <span class="string">&quot;*&quot;</span></span><br></pre></td></tr></table></figure>

<blockquote>
<p>3、直接访问:<code>http://localhost/actuator/routes</code></p>
</blockquote>
<p><img src="/posts/java/springcloud/1/images/image-20201112132217601.png" alt="image-20201112132217601"></p>
<h4 id="6-3-2-忽略服务设置"><a href="#6-3-2-忽略服务设置" class="headerlink" title="6.3.2 忽略服务设置"></a>6.3.2 忽略服务设置</h4><figure class="highlight yml"><table><tr><td class="code"><pre><span class="line"><span class="comment"># zuul的配置</span></span><br><span class="line"><span class="attr">zuul:</span></span><br><span class="line">  <span class="comment">#基于服务名忽略服务，无法查看,如果要忽略全部的服务，&quot;*&quot;,默认配置的全部路径都会被忽略掉（自定义服务配置，通过这种方式是无法忽略的）</span></span><br><span class="line">  <span class="attr">ignored-services:</span> <span class="string">eureka</span></span><br><span class="line">  <span class="comment">#监考界面依然可以查看，在访问的时候，404无法访问</span></span><br><span class="line">  <span class="attr">ignored-patterns:</span> <span class="string">/**/search/**</span></span><br></pre></td></tr></table></figure>

<h4 id="6-3-3-自定义服务配置"><a href="#6-3-3-自定义服务配置" class="headerlink" title="6.3.3 自定义服务配置"></a>6.3.3 自定义服务配置</h4><figure class="highlight yml"><table><tr><td class="code"><pre><span class="line"><span class="comment"># zuul的配置</span></span><br><span class="line"><span class="attr">zuul:</span></span><br><span class="line">  <span class="comment">#基于服务名忽略服务，无法查看,如果要忽略全部的服务，&quot;*&quot;,默认配置的全部路径都会被忽略掉（自定义服务配置，通过这种方式是无法忽略的）</span></span><br><span class="line">  <span class="attr">ignored-services:</span> <span class="string">&quot;*&quot;</span></span><br><span class="line">  <span class="comment">#监考界面依然可以查看，在访问的时候，404无法访问</span></span><br><span class="line">  <span class="attr">ignored-patterns:</span> <span class="string">/**/search/**</span></span><br><span class="line">  <span class="comment"># 指定自定义服务（方式一，key(服务名):value(路径)）</span></span><br><span class="line"><span class="comment">#  routes:</span></span><br><span class="line"><span class="comment">#    search: /ss/**</span></span><br><span class="line"><span class="comment">#    customer: /cc/**</span></span><br><span class="line">  <span class="comment"># 指定自定义服务（方式二）</span></span><br><span class="line">  <span class="attr">routes:</span></span><br><span class="line">    <span class="attr">kehu:</span> <span class="comment">#自定义名称</span></span><br><span class="line">      <span class="attr">path:</span> <span class="string">/cc/**</span>  <span class="comment"># 映射路径</span></span><br><span class="line">      <span class="attr">serviceId:</span> <span class="string">customer</span></span><br></pre></td></tr></table></figure>

<h4 id="6-3-4-灰度发布"><a href="#6-3-4-灰度发布" class="headerlink" title="6.3.4 灰度发布"></a>6.3.4 灰度发布</h4><blockquote>
<p>1、添加一个配置类</p>
</blockquote>
<figure class="highlight java"><table><tr><td class="code"><pre><span class="line"><span class="meta">@Configuration</span></span><br><span class="line"><span class="keyword">public</span> <span class="class"><span class="keyword">class</span> <span class="title">ZuulConfig</span> </span>&#123;</span><br><span class="line">    <span class="meta">@Bean</span></span><br><span class="line">    <span class="function"><span class="keyword">public</span> PatternServiceRouteMapper <span class="title">serviceRouteMapper</span><span class="params">()</span> </span>&#123;</span><br><span class="line">        <span class="keyword">return</span> <span class="keyword">new</span> PatternServiceRouteMapper(</span><br><span class="line">                <span class="string">&quot;(?&lt;name&gt;^.+)-(?&lt;version&gt;v.+$)&quot;</span>,</span><br><span class="line">                <span class="string">&quot;$&#123;version&#125;/$&#123;name&#125;&quot;</span>);</span><br><span class="line">        <span class="comment">//服务名-v版本</span></span><br><span class="line">        <span class="comment">//    /v版本/路径</span></span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>

<blockquote>
<p>2、准备一个服务，提供2个版本</p>
</blockquote>
<figure class="highlight yml"><table><tr><td class="code"><pre><span class="line"><span class="attr">version:</span> <span class="string">v1</span></span><br><span class="line"></span><br><span class="line"><span class="comment">#指定服务名称</span></span><br><span class="line"><span class="attr">spring:</span></span><br><span class="line">  <span class="attr">application:</span></span><br><span class="line">    <span class="attr">name:</span> <span class="string">CUSTOMER-$&#123;version&#125;</span></span><br></pre></td></tr></table></figure>

<blockquote>
<p>3、修改Zuul的配置</p>
</blockquote>
<figure class="highlight yml"><table><tr><td class="code"><pre><span class="line"><span class="attr">zuul:</span></span><br><span class="line">  <span class="comment">#基于服务名忽略服务，无法查看,如果需要用到-v的方式，一定要忽略掉</span></span><br><span class="line"><span class="comment">#  ignored-services: &quot;*&quot;</span></span><br></pre></td></tr></table></figure>

<blockquote>
<p>4、修改CustomerController</p>
</blockquote>
<figure class="highlight java"><table><tr><td class="code"><pre><span class="line"><span class="meta">@Value(&quot;$&#123;version&#125;&quot;)</span></span><br><span class="line">  <span class="keyword">private</span> String version;</span><br><span class="line"></span><br><span class="line"><span class="meta">@GetMapping(&quot;/version&quot;)</span></span><br><span class="line">  <span class="function"><span class="keyword">public</span> String <span class="title">version</span><span class="params">()</span> </span>&#123;</span><br><span class="line">    <span class="keyword">return</span> version;</span><br><span class="line">  &#125;</span><br></pre></td></tr></table></figure>

<blockquote>
<p>5、测试</p>
</blockquote>
<p><img src="/posts/java/springcloud/1/images/image-20201112135410803.png" alt="image-20201112135410803"></p>
<p><img src="/posts/java/springcloud/1/images/image-20201112135429409.png" alt="image-20201112135429409"></p>
<h3 id="6-4-Zuul的过滤器执行流程"><a href="#6-4-Zuul的过滤器执行流程" class="headerlink" title="6.4 Zuul的过滤器执行流程"></a>6.4 Zuul的过滤器执行流程</h3><blockquote>
<p>客户端请求发送到Zuul服务商，首先通过PreFilter,如果正常放行，会把请求再次转发给RoutingFilter，请求转发到一个指定的服务，在指定的服务响应一个结果之后，再次走一个PostFilter的过滤器链，最终将响应信息返回给客户端。</p>
</blockquote>
<p><img src="/posts/java/springcloud/1/images/image-20201112140312697.png" alt="image-20201112140312697"></p>
<h3 id="6-5-Zuul过滤器入门"><a href="#6-5-Zuul过滤器入门" class="headerlink" title="6.5 Zuul过滤器入门"></a>6.5 Zuul过滤器入门</h3><blockquote>
<p>1、创建POJO类，继承ZuulFilter</p>
</blockquote>
<figure class="highlight java"><table><tr><td class="code"><pre><span class="line"><span class="meta">@Component</span></span><br><span class="line"><span class="keyword">public</span> <span class="class"><span class="keyword">class</span> <span class="title">ZuulFilterTest</span> <span class="keyword">extends</span> <span class="title">ZuulFilter</span> </span>&#123;</span><br><span class="line"></span><br><span class="line">&#125;</span><br><span class="line"></span><br></pre></td></tr></table></figure>

<blockquote>
<p>2、指定当前过滤器的类型</p>
</blockquote>
<figure class="highlight java"><table><tr><td class="code"><pre><span class="line"><span class="meta">@Override</span></span><br><span class="line"><span class="function"><span class="keyword">public</span> String <span class="title">filterType</span><span class="params">()</span> </span>&#123;</span><br><span class="line">    <span class="keyword">return</span> FilterConstants.PRE_TYPE;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>

<blockquote>
<p>3、指定过滤器的执行顺序</p>
</blockquote>
<figure class="highlight java"><table><tr><td class="code"><pre><span class="line"><span class="meta">@Override</span></span><br><span class="line"><span class="function"><span class="keyword">public</span> <span class="keyword">int</span> <span class="title">filterOrder</span><span class="params">()</span> </span>&#123;</span><br><span class="line">    <span class="keyword">return</span> FilterConstants.PRE_DECORATION_FILTER_ORDER -<span class="number">1</span>;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>

<blockquote>
<p>4、配置是否启用</p>
</blockquote>
<figure class="highlight java"><table><tr><td class="code"><pre><span class="line"><span class="meta">@Override</span></span><br><span class="line"><span class="function"><span class="keyword">public</span> <span class="keyword">boolean</span> <span class="title">shouldFilter</span><span class="params">()</span> </span>&#123;</span><br><span class="line">    <span class="comment">//开启当前过滤器</span></span><br><span class="line">    <span class="keyword">return</span> <span class="keyword">true</span>;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>

<blockquote>
<p>5、指定过滤器中的具体业务代码</p>
</blockquote>
<figure class="highlight java"><table><tr><td class="code"><pre><span class="line"><span class="meta">@Override</span></span><br><span class="line"><span class="function"><span class="keyword">public</span> Object <span class="title">run</span><span class="params">()</span> <span class="keyword">throws</span> ZuulException </span>&#123;</span><br><span class="line">    System.out.println(<span class="string">&quot;prefix过滤器已经执行~~~&quot;</span>);</span><br><span class="line">    <span class="keyword">return</span> <span class="keyword">null</span>;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>

<blockquote>
<p>6、测试</p>
</blockquote>
<p><img src="/posts/java/springcloud/1/images/image-20201112141523371.png" alt="image-20201112141523371"></p>
<h3 id="6-6-PreFilter实现token校验"><a href="#6-6-PreFilter实现token校验" class="headerlink" title="6.6 PreFilter实现token校验"></a>6.6 PreFilter实现token校验</h3><blockquote>
<p>1、准备访问路径，请求参数专递token</p>
</blockquote>
<p><code>http://localhost/v1/customer/version?token=123</code></p>
<blockquote>
<p>2、创建AuthenticationFilter</p>
</blockquote>
<figure class="highlight java"><table><tr><td class="code"><pre><span class="line"><span class="meta">@Component</span></span><br><span class="line"><span class="keyword">public</span> <span class="class"><span class="keyword">class</span> <span class="title">AuthenticationFilter</span> <span class="keyword">extends</span> <span class="title">ZuulFilter</span></span>&#123;</span><br><span class="line">    <span class="meta">@Override</span></span><br><span class="line">    <span class="function"><span class="keyword">public</span> String <span class="title">filterType</span><span class="params">()</span> </span>&#123;</span><br><span class="line">        <span class="keyword">return</span> FilterConstants.PRE_TYPE;</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="meta">@Override</span></span><br><span class="line">    <span class="function"><span class="keyword">public</span> <span class="keyword">int</span> <span class="title">filterOrder</span><span class="params">()</span> </span>&#123;</span><br><span class="line">        <span class="keyword">return</span> FilterConstants.PRE_DECORATION_FILTER_ORDER - <span class="number">2</span>;</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="meta">@Override</span></span><br><span class="line">    <span class="function"><span class="keyword">public</span> <span class="keyword">boolean</span> <span class="title">shouldFilter</span><span class="params">()</span> </span>&#123;</span><br><span class="line">        <span class="keyword">return</span> <span class="keyword">true</span>;</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="meta">@Override</span></span><br><span class="line">    <span class="function"><span class="keyword">public</span> Object <span class="title">run</span><span class="params">()</span> <span class="keyword">throws</span> ZuulException </span>&#123;</span><br><span class="line">        <span class="comment">//...</span></span><br><span class="line">        <span class="keyword">return</span> <span class="keyword">null</span>;</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>

<blockquote>
<p>3、在run方法中编写具体的业务逻辑代码</p>
</blockquote>
<figure class="highlight java"><table><tr><td class="code"><pre><span class="line"><span class="meta">@Override</span></span><br><span class="line">    <span class="function"><span class="keyword">public</span> Object <span class="title">run</span><span class="params">()</span> <span class="keyword">throws</span> ZuulException </span>&#123;</span><br><span class="line">        System.out.println(<span class="string">&quot;AuthenticationFilter执行了&quot;</span>);</span><br><span class="line">        <span class="comment">//1. 获取Request对象</span></span><br><span class="line">        RequestContext requestContext = RequestContext.getCurrentContext();</span><br><span class="line">        HttpServletRequest request = requestContext.getRequest();</span><br><span class="line">        <span class="comment">//2. 获取token参数</span></span><br><span class="line">        String token = request.getParameter(<span class="string">&quot;token&quot;</span>);</span><br><span class="line">        <span class="comment">//3.对比token</span></span><br><span class="line">        <span class="keyword">if</span> (token == <span class="keyword">null</span> || !<span class="string">&quot;123&quot;</span>.equalsIgnoreCase(token)) &#123;</span><br><span class="line">            System.out.println(<span class="string">&quot;token校验失败&quot;</span>);</span><br><span class="line">            <span class="comment">//4. token校验失败，直接响应数据</span></span><br><span class="line">            requestContext.setSendZuulResponse(<span class="keyword">false</span>);</span><br><span class="line">            requestContext.setResponseStatusCode(HttpStatus.UNAUTHORIZED.value());</span><br><span class="line">        &#125;</span><br><span class="line">        <span class="keyword">return</span> <span class="keyword">null</span>;</span><br><span class="line">    &#125;</span><br></pre></td></tr></table></figure>

<blockquote>
<p>4、测试</p>
</blockquote>
<p><img src="/posts/java/springcloud/1/images/image-20201112145449105.png" alt="image-20201112145449105"></p>
<h3 id="6-7-Zuul的降级"><a href="#6-7-Zuul的降级" class="headerlink" title="6.7 Zuul的降级"></a>6.7 Zuul的降级</h3><blockquote>
<p>1、创建POJO类，实现接口FallbackProvider</p>
</blockquote>
<figure class="highlight java"><table><tr><td class="code"><pre><span class="line"><span class="meta">@Component</span></span><br><span class="line"><span class="keyword">public</span> <span class="class"><span class="keyword">class</span> <span class="title">ZuulFallBack</span> <span class="keyword">implements</span> <span class="title">FallbackProvider</span> </span>&#123;</span><br><span class="line"></span><br><span class="line">&#125;</span><br><span class="line"></span><br></pre></td></tr></table></figure>

<blockquote>
<p>2、重写两个方法</p>
</blockquote>
<figure class="highlight java"><table><tr><td class="code"><pre><span class="line"><span class="meta">@Override</span></span><br><span class="line"><span class="function"><span class="keyword">public</span> String <span class="title">getRoute</span><span class="params">()</span> </span>&#123;</span><br><span class="line">    <span class="comment">//代表指定全部出现问题的服务，都走这个降级方法</span></span><br><span class="line">    <span class="keyword">return</span> <span class="string">&quot;*&quot;</span>;</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="meta">@Override</span></span><br><span class="line"><span class="function"><span class="keyword">public</span> ClientHttpResponse <span class="title">fallbackResponse</span><span class="params">(String route, Throwable cause)</span> </span>&#123;</span><br><span class="line">    System.out.println(<span class="string">&quot;降级的服务&quot;</span>+route);</span><br><span class="line">    cause.printStackTrace();</span><br><span class="line">    <span class="keyword">return</span> <span class="keyword">new</span> ClientHttpResponse() &#123;</span><br><span class="line">        <span class="meta">@Override</span></span><br><span class="line">        <span class="function"><span class="keyword">public</span> HttpHeaders <span class="title">getHeaders</span><span class="params">()</span> </span>&#123;</span><br><span class="line">            <span class="comment">//指定响应头信息</span></span><br><span class="line">            HttpHeaders headers = <span class="keyword">new</span> HttpHeaders();</span><br><span class="line">            headers.setContentType(MediaType.APPLICATION_JSON);</span><br><span class="line">            <span class="keyword">return</span> headers;</span><br><span class="line">        &#125;</span><br><span class="line"></span><br><span class="line">        <span class="meta">@Override</span></span><br><span class="line">        <span class="function"><span class="keyword">public</span> InputStream <span class="title">getBody</span><span class="params">()</span> <span class="keyword">throws</span> IOException </span>&#123;</span><br><span class="line">            <span class="comment">//给用户响应的信息</span></span><br><span class="line">            String msg = <span class="string">&quot;当前服务&quot;</span> + route + <span class="string">&quot;出现问题！！！&quot;</span>;</span><br><span class="line">            <span class="keyword">return</span> <span class="keyword">new</span> ByteArrayInputStream(msg.getBytes());</span><br><span class="line">        &#125;</span><br><span class="line"></span><br><span class="line">        <span class="meta">@Override</span></span><br><span class="line">        <span class="function"><span class="keyword">public</span> HttpStatus <span class="title">getStatusCode</span><span class="params">()</span> <span class="keyword">throws</span> IOException </span>&#123;</span><br><span class="line">            <span class="comment">//指定具体的HttpStatus</span></span><br><span class="line">            <span class="keyword">return</span> HttpStatus.INTERNAL_SERVER_ERROR;</span><br><span class="line">        &#125;</span><br><span class="line"></span><br><span class="line">        <span class="meta">@Override</span></span><br><span class="line">        <span class="function"><span class="keyword">public</span> <span class="keyword">int</span> <span class="title">getRawStatusCode</span><span class="params">()</span> <span class="keyword">throws</span> IOException </span>&#123;</span><br><span class="line">            <span class="comment">//返回状态码</span></span><br><span class="line">            <span class="keyword">return</span> HttpStatus.INTERNAL_SERVER_ERROR.value();</span><br><span class="line">        &#125;</span><br><span class="line"></span><br><span class="line">        <span class="meta">@Override</span></span><br><span class="line">        <span class="function"><span class="keyword">public</span> String <span class="title">getStatusText</span><span class="params">()</span> <span class="keyword">throws</span> IOException </span>&#123;</span><br><span class="line">            <span class="comment">//指定错误信息</span></span><br><span class="line">            <span class="keyword">return</span> HttpStatus.INTERNAL_SERVER_ERROR.getReasonPhrase();</span><br><span class="line">        &#125;</span><br><span class="line"></span><br><span class="line">        <span class="meta">@Override</span></span><br><span class="line">        <span class="function"><span class="keyword">public</span> <span class="keyword">void</span> <span class="title">close</span><span class="params">()</span> </span>&#123;</span><br><span class="line"></span><br><span class="line">        &#125;</span><br><span class="line">    &#125;;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>

<blockquote>
<p>3、测试</p>
</blockquote>
<p><img src="/posts/java/springcloud/1/images/image-20201112151632111.png" alt="image-20201112151632111"></p>
<h3 id="6-8-Zuul动态路由"><a href="#6-8-Zuul动态路由" class="headerlink" title="6.8 Zuul动态路由"></a>6.8 Zuul动态路由</h3><blockquote>
<p>1、创建一个过滤器</p>
</blockquote>
<figure class="highlight java"><table><tr><td class="code"><pre><span class="line"><span class="meta">@Component</span></span><br><span class="line"><span class="keyword">public</span> <span class="class"><span class="keyword">class</span> <span class="title">DynamicRoutingFilter</span>  <span class="keyword">extends</span> <span class="title">ZuulFilter</span></span>&#123;</span><br><span class="line"></span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>

<blockquote>
<p>2、在run方法中编辑业务逻辑</p>
</blockquote>
<figure class="highlight java"><table><tr><td class="code"><pre><span class="line"><span class="meta">@Override</span></span><br><span class="line"><span class="function"><span class="keyword">public</span> String <span class="title">filterType</span><span class="params">()</span> </span>&#123;</span><br><span class="line">    <span class="keyword">return</span> FilterConstants.PRE_TYPE;</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="meta">@Override</span></span><br><span class="line"><span class="function"><span class="keyword">public</span> <span class="keyword">int</span> <span class="title">filterOrder</span><span class="params">()</span> </span>&#123;</span><br><span class="line">    <span class="keyword">return</span> FilterConstants.PRE_DECORATION_FILTER_ORDER +<span class="number">3</span>;</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="meta">@Override</span></span><br><span class="line"><span class="function"><span class="keyword">public</span> <span class="keyword">boolean</span> <span class="title">shouldFilter</span><span class="params">()</span> </span>&#123;</span><br><span class="line">    <span class="keyword">return</span> <span class="keyword">true</span>;</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="meta">@Override</span></span><br><span class="line"><span class="function"><span class="keyword">public</span> Object <span class="title">run</span><span class="params">()</span> <span class="keyword">throws</span> ZuulException </span>&#123;</span><br><span class="line">    System.out.println(<span class="string">&quot;DynamicRoutingFilter执行了&quot;</span>);</span><br><span class="line">    <span class="comment">//1、获取Request对象</span></span><br><span class="line">    RequestContext context = RequestContext.getCurrentContext();</span><br><span class="line">    HttpServletRequest request = context.getRequest();</span><br><span class="line"></span><br><span class="line">    <span class="comment">//2、获取参数，redisKey</span></span><br><span class="line">    String redisKey = request.getParameter(<span class="string">&quot;redisKey&quot;</span>);</span><br><span class="line"></span><br><span class="line">    <span class="comment">//3、直接判断</span></span><br><span class="line">    <span class="keyword">if</span> (redisKey != <span class="keyword">null</span> &amp;&amp; redisKey.equalsIgnoreCase(<span class="string">&quot;customer&quot;</span>)) &#123;</span><br><span class="line">        System.out.println(<span class="string">&quot;DynamicRoutingFilter执行了路由到了/customer&quot;</span>);</span><br><span class="line">        <span class="comment">//http://localhost:8080/customer</span></span><br><span class="line">        context.put(FilterConstants.SERVICE_ID_KEY,<span class="string">&quot;customer-v1&quot;</span>);</span><br><span class="line">        context.put(FilterConstants.REQUEST_URI_KEY,<span class="string">&quot;/customer&quot;</span>);</span><br><span class="line">    &#125; <span class="keyword">else</span> <span class="keyword">if</span> (redisKey != <span class="keyword">null</span> &amp;&amp; redisKey.equalsIgnoreCase(<span class="string">&quot;search&quot;</span>)) &#123;</span><br><span class="line">        System.out.println(<span class="string">&quot;DynamicRoutingFilter执行了路由到了/search/1&quot;</span>);</span><br><span class="line">        <span class="comment">//http://localhost:8081/search</span></span><br><span class="line">        context.put(FilterConstants.SERVICE_ID_KEY,<span class="string">&quot;search&quot;</span>);</span><br><span class="line">        context.put(FilterConstants.REQUEST_URI_KEY,<span class="string">&quot;/search/1&quot;</span>);</span><br><span class="line">    &#125;</span><br><span class="line">    <span class="keyword">return</span> <span class="keyword">null</span>;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>

<blockquote>
<p>3、测试</p>
</blockquote>
<p><img src="/posts/java/springcloud/1/images/image-20201112155707148.png" alt="image-20201112155707148"></p>
<p><img src="/posts/java/springcloud/1/images/image-20201112155652269.png" alt="image-20201112155652269"></p>
<h2 id="七、多语言支持-Sidecar"><a href="#七、多语言支持-Sidecar" class="headerlink" title="七、多语言支持-Sidecar"></a>七、多语言支持-Sidecar</h2><h3 id="7-1-引言"><a href="#7-1-引言" class="headerlink" title="7.1 引言"></a>7.1 引言</h3><blockquote>
<p>在SpringCloud的项目中，需要接入一些非java程序，第三方接口，无法接入eureka，hystrix，feign等组件。启动一个代理的微服务，代理微服务去和非java的程序或第三方接口交流，通过代理的非服务去计入SpringCloud的相关组件。</p>
</blockquote>
<p><img src="/posts/java/springcloud/1/images/image-20201112160258956.png" alt="image-20201112160258956"></p>
<h3 id="7-2-Sidecar实现"><a href="#7-2-Sidecar实现" class="headerlink" title="7.2 Sidecar实现"></a>7.2 Sidecar实现</h3><blockquote>
<p>1、创建一个第三方的服务</p>
</blockquote>
<p><code>创建一个SpringBoot工程，并且添加一个Controller</code></p>
<blockquote>
<p>2、创建Maven工程，修改为SpringBoot</p>
</blockquote>
<blockquote>
<p>2、导入以来</p>
</blockquote>
<figure class="highlight xml"><table><tr><td class="code"><pre><span class="line"><span class="tag">&lt;<span class="name">dependency</span>&gt;</span></span><br><span class="line">    <span class="tag">&lt;<span class="name">groupId</span>&gt;</span>org.springframework.cloud<span class="tag">&lt;/<span class="name">groupId</span>&gt;</span></span><br><span class="line">    <span class="tag">&lt;<span class="name">artifactId</span>&gt;</span>spring-cloud-starter-netflix-eureka-client<span class="tag">&lt;/<span class="name">artifactId</span>&gt;</span></span><br><span class="line"><span class="tag">&lt;/<span class="name">dependency</span>&gt;</span></span><br><span class="line"><span class="tag">&lt;<span class="name">dependency</span>&gt;</span></span><br><span class="line">    <span class="tag">&lt;<span class="name">groupId</span>&gt;</span>org.springframework.cloud<span class="tag">&lt;/<span class="name">groupId</span>&gt;</span></span><br><span class="line">    <span class="tag">&lt;<span class="name">artifactId</span>&gt;</span>spring-cloud-netflix-sidecar<span class="tag">&lt;/<span class="name">artifactId</span>&gt;</span></span><br><span class="line"><span class="tag">&lt;/<span class="name">dependency</span>&gt;</span></span><br></pre></td></tr></table></figure>

<blockquote>
<p>4、添加注解<code>@EnableSidecar</code></p>
</blockquote>
<blockquote>
<p>5、编写配置文件</p>
</blockquote>
<figure class="highlight yml"><table><tr><td class="code"><pre><span class="line"><span class="attr">server:</span></span><br><span class="line">  <span class="attr">port:</span> <span class="number">81</span></span><br><span class="line"></span><br><span class="line"><span class="attr">eureka:</span></span><br><span class="line">  <span class="attr">client:</span></span><br><span class="line">    <span class="attr">service-url:</span></span><br><span class="line">      <span class="attr">defaultZone:</span>  <span class="string">http://root:root@localhost:8761/eureka,http://root:root@localhost:8762/eureka</span></span><br><span class="line"></span><br><span class="line"><span class="comment">#指定服务名称</span></span><br><span class="line"><span class="attr">spring:</span></span><br><span class="line">  <span class="attr">application:</span></span><br><span class="line">    <span class="attr">name:</span> <span class="string">OTHER-SERVICE</span>    <span class="comment">#other-service</span></span><br><span class="line"></span><br><span class="line"><span class="comment"># 指定代理的第三方服务</span></span><br><span class="line"><span class="attr">sidecar:</span></span><br><span class="line">  <span class="attr">port:</span> <span class="number">7001</span></span><br></pre></td></tr></table></figure>

<blockquote>
<p>6、通过customer通过Feign的方式调用第三方服务</p>
</blockquote>
<p><img src="/posts/java/springcloud/1/images/image-20201112165325023.png" alt="image-20201112165325023"></p>
<h2 id="八、服务间消息传递-Stream"><a href="#八、服务间消息传递-Stream" class="headerlink" title="八、服务间消息传递-Stream"></a>八、服务间消息传递-Stream</h2><h3 id="8-1-引言"><a href="#8-1-引言" class="headerlink" title="8.1 引言"></a>8.1 引言</h3><blockquote>
<p>用于构建消息驱动微服务的框架(在下面方便起见也叫它Stream框架)，该框架在Spring Boot的基础上整合了Spring Integration来连接消息代理中间件（RabbitMQ，Kafka等）。它支持多个消息中间件的自定义配置，同时吸收了这些消息中间件的部分概念，例如持久化订阅、消费者分组，和分区等概念。使用Stream框架，我们不必关系如何连接各个消息代理中间件，也不必关系消息的发送与接收，只需要进行简单的配置就可以实现这些功能了，可以让我们更敏捷的进行开发主体业务逻辑了。</p>
<p><strong>Spring Cloud Stream框架的组成部分：</strong></p>
<ol>
<li>Stream框架自己的应用模型；</li>
<li>绑定器抽象层，可以与消息代理中间件进行绑定，通过绑定器的API，可实现插件式的绑定器。</li>
<li>持久化订阅的支持。</li>
<li>消费者组的支持。</li>
<li>Topic分区的支持。</li>
</ol>
</blockquote>
<p><img src="/posts/java/springcloud/1/images/20190325232054468.png" alt="image-20201112165641574"></p>
<h3 id="8-2-Stream快速入门"><a href="#8-2-Stream快速入门" class="headerlink" title="8.2 Stream快速入门"></a>8.2 Stream快速入门</h3><blockquote>
<p>1、启动RabbitMQ</p>
</blockquote>
<blockquote>
<p>2、消费者-导入依赖</p>
</blockquote>
<figure class="highlight xml"><table><tr><td class="code"><pre><span class="line"><span class="tag">&lt;<span class="name">dependency</span>&gt;</span></span><br><span class="line">    <span class="tag">&lt;<span class="name">groupId</span>&gt;</span>org.springframework.cloud<span class="tag">&lt;/<span class="name">groupId</span>&gt;</span></span><br><span class="line">    <span class="tag">&lt;<span class="name">artifactId</span>&gt;</span>spring-cloud-starter-stream-rabbit<span class="tag">&lt;/<span class="name">artifactId</span>&gt;</span></span><br><span class="line"><span class="tag">&lt;/<span class="name">dependency</span>&gt;</span></span><br></pre></td></tr></table></figure>

<blockquote>
<p>3、消费者-配置文件</p>
</blockquote>
<figure class="highlight yml"><table><tr><td class="code"><pre><span class="line"><span class="attr">spring:</span></span><br><span class="line">  <span class="attr">rabbitmq:</span></span><br><span class="line">    <span class="attr">port:</span> <span class="number">5672</span></span><br><span class="line">    <span class="attr">username:</span> <span class="string">test</span></span><br><span class="line">    <span class="attr">password:</span> <span class="string">test</span></span><br><span class="line">    <span class="attr">virtual-host:</span> <span class="string">/test</span></span><br></pre></td></tr></table></figure>

<blockquote>
<p>4、消费者-监听的队列</p>
</blockquote>
<figure class="highlight java"><table><tr><td class="code"><pre><span class="line"><span class="keyword">public</span> <span class="class"><span class="keyword">interface</span> <span class="title">StreamClient</span> </span>&#123;</span><br><span class="line">    <span class="meta">@Input(&quot;myMessage&quot;)</span></span><br><span class="line">    <span class="function">SubscribableChannel <span class="title">input</span><span class="params">()</span></span>;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>

<figure class="highlight java"><table><tr><td class="code"><pre><span class="line"><span class="meta">@Component</span></span><br><span class="line"><span class="meta">@EnableBinding(StreamClient.class)</span></span><br><span class="line"><span class="keyword">public</span> <span class="class"><span class="keyword">class</span> <span class="title">StreamReceiver</span> </span>&#123;</span><br><span class="line">    <span class="meta">@StreamListener(&quot;myMessage&quot;)</span></span><br><span class="line">    <span class="function"><span class="keyword">public</span> <span class="keyword">void</span> <span class="title">msg</span><span class="params">(Object msg)</span> </span>&#123;</span><br><span class="line">        System.out.println(<span class="string">&quot;接收到消息&quot;</span> + msg);</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>

<blockquote>
<p>5、启动类添加注解<code>@EnableBinding(StreamClient.class)</code></p>
</blockquote>
<blockquote>
<p>6、生产者-导入依赖</p>
</blockquote>
<figure class="highlight xml"><table><tr><td class="code"><pre><span class="line"><span class="tag">&lt;<span class="name">dependency</span>&gt;</span></span><br><span class="line">    <span class="tag">&lt;<span class="name">groupId</span>&gt;</span>org.springframework.cloud<span class="tag">&lt;/<span class="name">groupId</span>&gt;</span></span><br><span class="line">    <span class="tag">&lt;<span class="name">artifactId</span>&gt;</span>spring-cloud-starter-stream-rabbit<span class="tag">&lt;/<span class="name">artifactId</span>&gt;</span></span><br><span class="line"><span class="tag">&lt;/<span class="name">dependency</span>&gt;</span></span><br></pre></td></tr></table></figure>

<blockquote>
<p>7、生产者-配置文件</p>
</blockquote>
<figure class="highlight yml"><table><tr><td class="code"><pre><span class="line"><span class="attr">spring:</span></span><br><span class="line">  <span class="attr">rabbitmq:</span></span><br><span class="line">    <span class="attr">port:</span> <span class="number">5672</span></span><br><span class="line">    <span class="attr">username:</span> <span class="string">test</span></span><br><span class="line">    <span class="attr">password:</span> <span class="string">test</span></span><br><span class="line">    <span class="attr">virtual-host:</span> <span class="string">/test</span></span><br></pre></td></tr></table></figure>

<blockquote>
<p>8、生产者-发布消息</p>
</blockquote>
<figure class="highlight java"><table><tr><td class="code"><pre><span class="line"><span class="keyword">public</span> <span class="class"><span class="keyword">interface</span> <span class="title">StreamClient</span> </span>&#123;</span><br><span class="line">    <span class="meta">@Output(&quot;myMessage&quot;)</span></span><br><span class="line">    <span class="function">MessageChannel <span class="title">output</span><span class="params">()</span></span>;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>

<figure class="highlight java"><table><tr><td class="code"><pre><span class="line"><span class="meta">@RestController</span></span><br><span class="line"><span class="keyword">public</span> <span class="class"><span class="keyword">class</span> <span class="title">MessageController</span> </span>&#123;</span><br><span class="line">    <span class="meta">@Autowired</span></span><br><span class="line">    <span class="keyword">private</span> StreamClient streamClient;</span><br><span class="line">    <span class="meta">@GetMapping(&quot;/send&quot;)</span></span><br><span class="line">    <span class="function"><span class="keyword">public</span> String <span class="title">send</span><span class="params">()</span> </span>&#123;</span><br><span class="line">        streamClient.output().send(MessageBuilder.withPayload(<span class="string">&quot;Hello Stream&quot;</span>).build());</span><br><span class="line">        <span class="keyword">return</span> <span class="string">&quot;消息发送成功！！&quot;</span>;</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>

<blockquote>
<p>9、启动类添加注解<code>@EnableBinding(StreamClient.class)</code></p>
</blockquote>
<blockquote>
<p>10、测试访问<code>http://localhost:8080/send</code></p>
</blockquote>
<p><img src="/posts/java/springcloud/1/images/image-20201113093057704.png" alt="image-20201113093057704"></p>
<p><img src="/posts/java/springcloud/1/images/image-20201112173342142.png" alt="image-20201112173342142"></p>
<h3 id="8-3-Stream重复消费问题"><a href="#8-3-Stream重复消费问题" class="headerlink" title="8.3 Stream重复消费问题"></a>8.3 Stream重复消费问题</h3><blockquote>
<p>只需要添加一个配置，指定消费者组</p>
</blockquote>
<figure class="highlight yml"><table><tr><td class="code"><pre><span class="line"><span class="attr">spring:</span></span><br><span class="line">  <span class="attr">cloud:</span></span><br><span class="line">    <span class="attr">stream:</span></span><br><span class="line">      <span class="attr">binders:</span></span><br><span class="line">        <span class="attr">myMessage:</span>  <span class="comment">#队列名称</span></span><br><span class="line">          <span class="attr">group:</span> <span class="string">customer</span> <span class="comment">#消费者组</span></span><br></pre></td></tr></table></figure>

<h3 id="8-4-Stream的消费者手动ack"><a href="#8-4-Stream的消费者手动ack" class="headerlink" title="8.4 Stream的消费者手动ack"></a>8.4 Stream的消费者手动ack</h3><blockquote>
<p>1、编写配置</p>
</blockquote>
<figure class="highlight yml"><table><tr><td class="code"><pre><span class="line"><span class="comment">#指定服务名称</span></span><br><span class="line"><span class="attr">spring:</span></span><br><span class="line">  <span class="attr">cloud:</span></span><br><span class="line">    <span class="attr">stream:</span></span><br><span class="line">      <span class="comment">#实现手动ack</span></span><br><span class="line">      <span class="attr">rabbit:</span></span><br><span class="line">        <span class="attr">bindings:</span></span><br><span class="line">          <span class="attr">myMessage:</span></span><br><span class="line">            <span class="attr">consumer:</span></span><br><span class="line">              <span class="attr">acknowledgeMode:</span> <span class="string">MANUAL</span></span><br></pre></td></tr></table></figure>

<blockquote>
<p>2、修改消费端方法</p>
</blockquote>
<figure class="highlight java"><table><tr><td class="code"><pre><span class="line"><span class="meta">@Component</span></span><br><span class="line"><span class="meta">@EnableBinding(StreamClient.class)</span></span><br><span class="line"><span class="keyword">public</span> <span class="class"><span class="keyword">class</span> <span class="title">StreamReceiver</span> </span>&#123;</span><br><span class="line">    <span class="meta">@StreamListener(&quot;myMessage&quot;)</span></span><br><span class="line">    <span class="function"><span class="keyword">public</span> <span class="keyword">void</span> <span class="title">msg</span><span class="params">(Object msg,</span></span></span><br><span class="line"><span class="params"><span class="function">                    <span class="meta">@Header(name = AmqpHeaders.CHANNEL)</span> Channel channel,</span></span></span><br><span class="line"><span class="params"><span class="function">                    <span class="meta">@Header(name = AmqpHeaders.DELIVERY_TAG)</span> Long deliveryTag)</span> <span class="keyword">throws</span> IOException </span>&#123;</span><br><span class="line">        System.out.println(<span class="string">&quot;接收到消息&quot;</span> + msg);</span><br><span class="line">        channel.basicAck(deliveryTag,<span class="keyword">false</span>);</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>

<h2 id="九、服务的动态配置-Config"><a href="#九、服务的动态配置-Config" class="headerlink" title="九、服务的动态配置-Config"></a>九、服务的动态配置-Config</h2><h3 id="9-1-引言"><a href="#9-1-引言" class="headerlink" title="9.1 引言"></a>9.1 引言</h3><blockquote>
<p>1、配置文件分散在不同项目中的，不方便去维护。</p>
<p>2、配置文件的安全问题。</p>
<p>3、修改配置文件，无法立即生效。</p>
</blockquote>
<p><img src="/posts/java/springcloud/1/images/image-20201112180552221.png" alt="image-20201112180552221"></p>
<h3 id="9-2-搭建Config-Server"><a href="#9-2-搭建Config-Server" class="headerlink" title="9.2 搭建Config-Server"></a>9.2 搭建Config-Server</h3><blockquote>
<p>1、创建Maven工程，修改SpringBoot</p>
</blockquote>
<blockquote>
<p>2、导入依赖</p>
</blockquote>
<figure class="highlight xml"><table><tr><td class="code"><pre><span class="line"><span class="tag">&lt;<span class="name">dependency</span>&gt;</span></span><br><span class="line">    <span class="tag">&lt;<span class="name">groupId</span>&gt;</span>org.springframework.cloud<span class="tag">&lt;/<span class="name">groupId</span>&gt;</span></span><br><span class="line">    <span class="tag">&lt;<span class="name">artifactId</span>&gt;</span>spring-cloud-starter-netflix-eureka-client<span class="tag">&lt;/<span class="name">artifactId</span>&gt;</span></span><br><span class="line"><span class="tag">&lt;/<span class="name">dependency</span>&gt;</span></span><br><span class="line"><span class="tag">&lt;<span class="name">dependency</span>&gt;</span></span><br><span class="line">    <span class="tag">&lt;<span class="name">groupId</span>&gt;</span>org.springframework.cloud<span class="tag">&lt;/<span class="name">groupId</span>&gt;</span></span><br><span class="line">    <span class="tag">&lt;<span class="name">artifactId</span>&gt;</span>spring-cloud-config-server<span class="tag">&lt;/<span class="name">artifactId</span>&gt;</span></span><br><span class="line"><span class="tag">&lt;/<span class="name">dependency</span>&gt;</span></span><br></pre></td></tr></table></figure>

<blockquote>
<p>3、添加注解<code>@EnableConfigServer</code></p>
</blockquote>
<figure class="highlight java"><table><tr><td class="code"><pre><span class="line"><span class="meta">@SpringBootApplication</span></span><br><span class="line"><span class="meta">@EnableConfigServer</span></span><br><span class="line"><span class="keyword">public</span> <span class="class"><span class="keyword">class</span> <span class="title">ConfigApplication</span> </span>&#123;</span><br><span class="line">    <span class="function"><span class="keyword">public</span> <span class="keyword">static</span> <span class="keyword">void</span> <span class="title">main</span><span class="params">(String[] args)</span> </span>&#123;</span><br><span class="line">        SpringApplication.run(ConfigApplication.class,args);</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>

<blockquote>
<p>4、编写配置文件（git）</p>
</blockquote>
<figure class="highlight yml"><table><tr><td class="code"><pre><span class="line"><span class="attr">spring:</span></span><br><span class="line">  <span class="attr">cloud:</span></span><br><span class="line">    <span class="attr">config:</span></span><br><span class="line">      <span class="attr">server:</span></span><br><span class="line">        <span class="attr">git:</span></span><br><span class="line">          <span class="attr">basedir:</span>     <span class="string">E:\config</span> <span class="comment"># 本地仓库地址</span></span><br><span class="line">          <span class="attr">username:</span>    <span class="string">xxxxxx@xxxx.com</span> <span class="comment">#远程仓库的用户名</span></span><br><span class="line">          <span class="attr">password:</span>    <span class="string">xxxxxxxx</span> <span class="comment">#远程仓库的密码</span></span><br><span class="line">          <span class="attr">uri:</span> <span class="string">https://gitee.com/zyjblog/config-resp.git</span></span><br></pre></td></tr></table></figure>

<blockquote>
<p>5、测试(例子：<code>http://localhost:82/master/customer-xxx.yml</code> (master可以省略）)</p>
<p>访问方式如下:</p>
<p><code>/&#123;application&#125;/&#123;profile&#125;[/&#123;label&#125;]</code><br><code>/&#123;application&#125;-&#123;profile&#125;.yml</code><br><code>/&#123;label&#125;/&#123;application&#125;-&#123;profile&#125;.yml</code></p>
<p><code>/&#123;application&#125;-&#123;profile&#125;.properties</code><br><code>/&#123;label&#125;/&#123;application&#125;-&#123;profile&#125;.properties</code></p>
</blockquote>
<p><img src="/posts/java/springcloud/1/images/image-20201113094055276.png" alt="image-20201113094055276"></p>
<h3 id="9-3、修改Customer连接Config"><a href="#9-3、修改Customer连接Config" class="headerlink" title="9.3、修改Customer连接Config"></a>9.3、修改Customer连接Config</h3><blockquote>
<p>1、导入依赖</p>
</blockquote>
<figure class="highlight yml"><table><tr><td class="code"><pre><span class="line"><span class="string">&lt;dependency&gt;</span></span><br><span class="line">    <span class="string">&lt;groupId&gt;org.springframework.cloud&lt;/groupId&gt;</span></span><br><span class="line">    <span class="string">&lt;artifactId&gt;spring-cloud-config-client&lt;/artifactId&gt;</span></span><br><span class="line"><span class="string">&lt;/dependency&gt;</span></span><br></pre></td></tr></table></figure>

<blockquote>
<p>2、修改配置文件</p>
</blockquote>
<figure class="highlight java"><table><tr><td class="code"><pre><span class="line">#指定Eureka服务地址</span><br><span class="line">eureka:</span><br><span class="line">  client:</span><br><span class="line">    service-url:</span><br><span class="line">      defaultZone: http:<span class="comment">//root:root@localhost:8761/eureka,http://root:root@localhost:8762/eureka</span></span><br><span class="line"></span><br><span class="line">version: v1</span><br><span class="line">#指定服务名称</span><br><span class="line">spring:</span><br><span class="line">  application:</span><br><span class="line">    name: CUSTOMER-$&#123;version&#125;</span><br><span class="line">  cloud:</span><br><span class="line">    config:</span><br><span class="line">      discovery:</span><br><span class="line">        enabled: <span class="keyword">true</span></span><br><span class="line">        service-id: CONFIG</span><br><span class="line">      profile: dev</span><br></pre></td></tr></table></figure>

<blockquote>
<p>3、修改配置文件名称<code>application.yml</code>改为<code>bootstrap.yml</code></p>
</blockquote>
<blockquote>
<p>4、测试测试发布消息到RabbMQ</p>
</blockquote>
<p><img src="/posts/java/springcloud/1/images/image-20201113102316294.png" alt="image-20201113102316294"></p>
<h3 id="9-4-实现动态配置"><a href="#9-4-实现动态配置" class="headerlink" title="9.4 实现动态配置"></a>9.4 实现动态配置</h3><h4 id="9-4-1-实现原理"><a href="#9-4-1-实现原理" class="headerlink" title="9.4.1 实现原理"></a>9.4.1 实现原理</h4><p><img src="/posts/java/springcloud/1/images/image-20201113103152115.png" alt="image-20201113103152115"></p>
<h4 id="9-4-2-服务连接RabbitMQ"><a href="#9-4-2-服务连接RabbitMQ" class="headerlink" title="9.4.2 服务连接RabbitMQ"></a>9.4.2 服务连接RabbitMQ</h4><blockquote>
<p>1、导入依赖</p>
</blockquote>
<figure class="highlight xml"><table><tr><td class="code"><pre><span class="line"><span class="tag">&lt;<span class="name">dependency</span>&gt;</span></span><br><span class="line">    <span class="tag">&lt;<span class="name">groupId</span>&gt;</span>org.springframework.cloud<span class="tag">&lt;/<span class="name">groupId</span>&gt;</span></span><br><span class="line">    <span class="tag">&lt;<span class="name">artifactId</span>&gt;</span>spring-cloud-starter-bus-amqp<span class="tag">&lt;/<span class="name">artifactId</span>&gt;</span></span><br><span class="line"><span class="tag">&lt;/<span class="name">dependency</span>&gt;</span></span><br></pre></td></tr></table></figure>

<blockquote>
<p>2、编写配置文件</p>
</blockquote>
<figure class="highlight yml"><table><tr><td class="code"><pre><span class="line"><span class="attr">spring:</span></span><br><span class="line">  <span class="attr">rabbitmq:</span></span><br><span class="line">    <span class="attr">virtual-host:</span> <span class="string">/test</span></span><br><span class="line">    <span class="attr">host:</span> <span class="string">localhost</span></span><br><span class="line">    <span class="attr">username:</span> <span class="string">test</span></span><br><span class="line">    <span class="attr">password:</span> <span class="string">test</span></span><br><span class="line">    <span class="attr">port:</span> <span class="number">5672</span></span><br></pre></td></tr></table></figure>

<blockquote>
<p>3、测试</p>
</blockquote>
<p><img src="/posts/java/springcloud/1/images/image-20201113104134210.png" alt="image-20201113104134210"></p>
<h4 id="9-4-3-实现手动刷新"><a href="#9-4-3-实现手动刷新" class="headerlink" title="9.4.3 实现手动刷新"></a>9.4.3 实现手动刷新</h4><blockquote>
<p>1、导入依赖(两个服务config和customer均添加)</p>
</blockquote>
<figure class="highlight xml"><table><tr><td class="code"><pre><span class="line"><span class="tag">&lt;<span class="name">dependency</span>&gt;</span></span><br><span class="line">    <span class="tag">&lt;<span class="name">groupId</span>&gt;</span>org.springframework.boot<span class="tag">&lt;/<span class="name">groupId</span>&gt;</span></span><br><span class="line">    <span class="tag">&lt;<span class="name">artifactId</span>&gt;</span>spring-boot-starter-actuator<span class="tag">&lt;/<span class="name">artifactId</span>&gt;</span></span><br><span class="line"><span class="tag">&lt;/<span class="name">dependency</span>&gt;</span></span><br></pre></td></tr></table></figure>

<blockquote>
<p>2、编写配置文件(两个服务config和customer均添加)</p>
</blockquote>
<figure class="highlight yml"><table><tr><td class="code"><pre><span class="line"><span class="attr">management:</span></span><br><span class="line">  <span class="attr">endpoints:</span></span><br><span class="line">    <span class="attr">web:</span></span><br><span class="line">      <span class="attr">exposure:</span></span><br><span class="line">        <span class="attr">include:</span> <span class="string">&quot;*&quot;</span></span><br></pre></td></tr></table></figure>

<blockquote>
<p>3、为customer添加一个controller,添加注解<code>@RefreshScope</code></p>
</blockquote>
<figure class="highlight java"><table><tr><td class="code"><pre><span class="line"><span class="meta">@RestController</span></span><br><span class="line"><span class="meta">@RefreshScope</span></span><br><span class="line"><span class="keyword">public</span> <span class="class"><span class="keyword">class</span> <span class="title">CustomerController</span> </span>&#123;</span><br><span class="line"></span><br><span class="line">    <span class="meta">@Value(&quot;$&#123;env&#125;&quot;)</span></span><br><span class="line">    <span class="keyword">private</span> String env;</span><br><span class="line"></span><br><span class="line">    <span class="meta">@GetMapping(&quot;/env&quot;)</span></span><br><span class="line">    <span class="function"><span class="keyword">public</span> String <span class="title">env</span><span class="params">()</span> </span>&#123;</span><br><span class="line">        <span class="keyword">return</span> env;</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>

<blockquote>
<p>4、测试</p>
<ol>
<li>CONFIG在gitee修改之后，自动拉取最新的配置信息。</li>
<li>其他模块需要更新的话，手动发送一个POST请求：<a target="_blank" rel="noopener" href="http://localhost:10000/actuator/bus-refresh">http://localhost:10000/actuator/bus-refresh</a> ，不重启项目，即可获取最新的配置信息</li>
</ol>
</blockquote>
<h4 id="9-4-4-内网穿透"><a href="#9-4-4-内网穿透" class="headerlink" title="9.4.4 内网穿透"></a>9.4.4 内网穿透</h4><blockquote>
<p>1、内网穿透官网：<a target="_blank" rel="noopener" href="http://www.ngrok.cc/">http://www.ngrok.cc/</a></p>
</blockquote>
<blockquote>
<p>2、注册登录</p>
</blockquote>
<blockquote>
<p>3、购买免费隧道，并配置</p>
</blockquote>
<p><img src="/posts/java/springcloud/1/images/image-20201113113814310.png" alt="image-20201113113814310"></p>
<blockquote>
<p>4、下载客户端，并复制隧道id，点击运行客户端，复制到客户端中</p>
</blockquote>
<p><img src="/posts/java/springcloud/1/images/image-20201113114050201.png" alt="image-20201113114050201"></p>
<blockquote>
<p>5、测试访问是否成功</p>
</blockquote>
<p><img src="/posts/java/springcloud/1/images/image-20201113114131931.png" alt="image-20201113114131931"></p>
<h4 id="9-4-5-实现自动刷新配置"><a href="#9-4-5-实现自动刷新配置" class="headerlink" title="9.4.5 实现自动刷新配置"></a>9.4.5 实现自动刷新配置</h4><blockquote>
<p>1、配置Gitee中的WebHooks</p>
</blockquote>
<p><img src="/posts/java/springcloud/1/images/image-20201113120733998.png" alt="image-20201113120733998"></p>
<blockquote>
<p>2、给Config添加一个过滤器UrlFilter</p>
</blockquote>
<figure class="highlight java"><table><tr><td class="code"><pre><span class="line"></span><br><span class="line"><span class="meta">@WebFilter(&quot;/*&quot;)</span></span><br><span class="line"><span class="keyword">public</span>  <span class="class"><span class="keyword">class</span> <span class="title">UrlFilter</span> <span class="keyword">implements</span> <span class="title">Filter</span> </span>&#123;</span><br><span class="line">    <span class="meta">@Override</span></span><br><span class="line">    <span class="function"><span class="keyword">public</span> <span class="keyword">void</span> <span class="title">doFilter</span><span class="params">(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain)</span> <span class="keyword">throws</span> IOException, ServletException </span>&#123;</span><br><span class="line">        HttpServletRequest httpServletRequest= (HttpServletRequest) servletRequest;</span><br><span class="line">        String url=httpServletRequest.getRequestURI();</span><br><span class="line">        System.out.println(url);</span><br><span class="line">        <span class="keyword">if</span>(!url.endsWith(<span class="string">&quot;/actuator/bus-refresh&quot;</span>))&#123;</span><br><span class="line">            filterChain.doFilter(servletRequest,servletResponse);</span><br><span class="line">            <span class="keyword">return</span>;</span><br><span class="line">        &#125;</span><br><span class="line">        String body=(httpServletRequest).toString();</span><br><span class="line">        System.out.println(<span class="string">&quot;original body: &quot;</span>+ body);</span><br><span class="line">        RequestWrapper requestWrapper=<span class="keyword">new</span> RequestWrapper(httpServletRequest);</span><br><span class="line">        filterChain.doFilter(requestWrapper,servletResponse);</span><br><span class="line">    &#125;</span><br><span class="line">    <span class="keyword">private</span> <span class="class"><span class="keyword">class</span> <span class="title">RequestWrapper</span> <span class="keyword">extends</span> <span class="title">HttpServletRequestWrapper</span> </span>&#123;</span><br><span class="line">        <span class="function"><span class="keyword">public</span> <span class="title">RequestWrapper</span><span class="params">(HttpServletRequest request)</span> </span>&#123;</span><br><span class="line">            <span class="keyword">super</span>(request);</span><br><span class="line">        &#125;</span><br><span class="line"></span><br><span class="line">        <span class="meta">@Override</span></span><br><span class="line">        <span class="function"><span class="keyword">public</span> ServletInputStream <span class="title">getInputStream</span><span class="params">()</span> <span class="keyword">throws</span> IOException </span>&#123;</span><br><span class="line">            <span class="keyword">byte</span>[] bytes = <span class="keyword">new</span> <span class="keyword">byte</span>[<span class="number">0</span>];</span><br><span class="line">            ByteArrayInputStream byteArrayInputStream = <span class="keyword">new</span> ByteArrayInputStream(bytes);</span><br><span class="line">            ServletInputStream servletInputStream = <span class="keyword">new</span> ServletInputStream() &#123;</span><br><span class="line">                <span class="meta">@Override</span></span><br><span class="line">                <span class="function"><span class="keyword">public</span> <span class="keyword">int</span> <span class="title">read</span><span class="params">()</span> <span class="keyword">throws</span> IOException </span>&#123;</span><br><span class="line">                    <span class="keyword">return</span> byteArrayInputStream.read();</span><br><span class="line">                &#125;</span><br><span class="line"></span><br><span class="line">                <span class="meta">@Override</span></span><br><span class="line">                <span class="function"><span class="keyword">public</span> <span class="keyword">boolean</span> <span class="title">isFinished</span><span class="params">()</span> </span>&#123;</span><br><span class="line">                    <span class="keyword">return</span> byteArrayInputStream.read() == -<span class="number">1</span> ? <span class="keyword">true</span> : <span class="keyword">false</span>;</span><br><span class="line">                &#125;</span><br><span class="line"></span><br><span class="line">                <span class="meta">@Override</span></span><br><span class="line">                <span class="function"><span class="keyword">public</span> <span class="keyword">boolean</span> <span class="title">isReady</span><span class="params">()</span> </span>&#123;</span><br><span class="line">                    <span class="keyword">return</span> <span class="keyword">false</span>;</span><br><span class="line">                &#125;</span><br><span class="line"></span><br><span class="line">                <span class="meta">@Override</span></span><br><span class="line">                <span class="function"><span class="keyword">public</span> <span class="keyword">void</span> <span class="title">setReadListener</span><span class="params">(ReadListener listener)</span> </span>&#123;</span><br><span class="line"></span><br><span class="line">                &#125;</span><br><span class="line">            &#125;;</span><br><span class="line">            <span class="keyword">return</span> servletInputStream;</span><br><span class="line">        &#125;</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>

<blockquote>
<p>3、添加注解<code>@ServletComponentScan(&quot;cn.zyjblogs.filter&quot;)</code></p>
</blockquote>
<figure class="highlight java"><table><tr><td class="code"><pre><span class="line"><span class="meta">@SpringBootApplication</span></span><br><span class="line"><span class="meta">@EnableConfigServer</span></span><br><span class="line"><span class="meta">@ServletComponentScan(&quot;cn.zyjblogs.filter&quot;)</span></span><br><span class="line"><span class="keyword">public</span> <span class="class"><span class="keyword">class</span> <span class="title">ConfigApplication</span> </span>&#123;</span><br><span class="line">    <span class="function"><span class="keyword">public</span> <span class="keyword">static</span> <span class="keyword">void</span> <span class="title">main</span><span class="params">(String[] args)</span> </span>&#123;</span><br><span class="line">        SpringApplication.run(ConfigApplication.class,args);</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>

<blockquote>
<p>3、测试</p>
</blockquote>
<p><img src="/posts/java/springcloud/1/images/image-20201113121035781.png" alt="image-20201113121035781"></p>
<h2 id="十、服务的追踪-Sleuth"><a href="#十、服务的追踪-Sleuth" class="headerlink" title="十、服务的追踪-Sleuth"></a>十、服务的追踪-Sleuth</h2><h3 id="10-1-引言"><a href="#10-1-引言" class="headerlink" title="10.1 引言"></a>10.1 引言</h3><blockquote>
<p>在整个微服务架构中，微服务很多，一个请求可能需要调用很多很多的服务，最终才能完成一个功能，如果说，整个功能出现了问题，在这么多的服务中，如何区定位到问题的所在点，出现问题的原因是什么。</p>
<p>1、Sleuth可以获取得到整个服务链路的信息</p>
<p>2、Zipkin通过图形化界面去看到信息。</p>
<p>3、Sleuth将日志信息存储到数据库中</p>
</blockquote>
<p><img src="/posts/java/springcloud/1/images/image-20201113131325996.png" alt="image-20201113131325996"></p>
<h3 id="10-2-Sleuth使用"><a href="#10-2-Sleuth使用" class="headerlink" title="10.2 Sleuth使用"></a>10.2 Sleuth使用</h3><blockquote>
<p>1、导入依赖</p>
</blockquote>
<figure class="highlight xml"><table><tr><td class="code"><pre><span class="line"><span class="tag">&lt;<span class="name">dependency</span>&gt;</span></span><br><span class="line">    <span class="tag">&lt;<span class="name">groupId</span>&gt;</span>org.springframework.cloud<span class="tag">&lt;/<span class="name">groupId</span>&gt;</span></span><br><span class="line">    <span class="tag">&lt;<span class="name">artifactId</span>&gt;</span>spring-cloud-starter-sleuth<span class="tag">&lt;/<span class="name">artifactId</span>&gt;</span></span><br><span class="line"><span class="tag">&lt;/<span class="name">dependency</span>&gt;</span></span><br></pre></td></tr></table></figure>

<blockquote>
<p>2、编写配置文件</p>
</blockquote>
<figure class="highlight yml"><table><tr><td class="code"><pre><span class="line"><span class="attr">logging:</span></span><br><span class="line">  <span class="attr">level:</span></span><br><span class="line">    <span class="attr">org.springframework.web.servlet.DispatcherServlet:</span> <span class="string">DEBUG</span></span><br></pre></td></tr></table></figure>

<blockquote>
<p>3、测试</p>
<p>SEARCH：服务名称</p>
<p>012 总链路id</p>
<p>b0e：当前服务的链路id</p>
<p>false：不会将当前的日志信息，输出到其他系统中</p>
</blockquote>
<p><img src="/posts/java/springcloud/1/images/image-20201113133658258.png" alt="image-20201113133658258"></p>
<p><img src="/posts/java/springcloud/1/images/image-20201113133713872.png" alt="image-20201113133713872"></p>
<p><img src="/posts/java/springcloud/1/images/image-20201113133745985.png" alt="image-20201113133745985"></p>
<h3 id="10-3-Zipkin的使用"><a href="#10-3-Zipkin的使用" class="headerlink" title="10.3 Zipkin的使用"></a>10.3 Zipkin的使用</h3><blockquote>
<p>1、搭建Zipkin的web工程 <a target="_blank" rel="noopener" href="https://zipkin.io/pages/quickstart">https://zipkin.io/pages/quickstart</a></p>
<ol>
<li>docker安装Zipkin</li>
</ol>
</blockquote>
<p>1、使用docker pull拉取</p>
<figure class="highlight bash"><table><tr><td class="code"><pre><span class="line">docker pull openzipkin/zipkin</span><br></pre></td></tr></table></figure>

<p>2、使用docker-compose</p>
<figure class="highlight yml"><table><tr><td class="code"><pre><span class="line"><span class="attr">version:</span> <span class="string">&quot;3.1&quot;</span></span><br><span class="line"><span class="attr">services:</span></span><br><span class="line">  <span class="attr">zipkin:</span></span><br><span class="line">    <span class="attr">image:</span> <span class="string">daocloud.io/daocloud/zipkin:latest</span></span><br><span class="line">    <span class="attr">restart:</span> <span class="string">always</span></span><br><span class="line">    <span class="attr">container_name:</span> <span class="string">zipkin</span></span><br><span class="line">    <span class="attr">ports:</span></span><br><span class="line">    <span class="bullet">-</span> <span class="number">9411</span><span class="string">:9411</span></span><br></pre></td></tr></table></figure>

<figure class="highlight bash"><table><tr><td class="code"><pre><span class="line">docker-compose up -d  <span class="comment">#启动</span></span><br><span class="line">docker-compose down   <span class="comment">#关闭</span></span><br></pre></td></tr></table></figure>

<blockquote>
<p>2、导入依赖</p>
</blockquote>
<figure class="highlight xml"><table><tr><td class="code"><pre><span class="line"><span class="tag">&lt;<span class="name">dependency</span>&gt;</span></span><br><span class="line">    <span class="tag">&lt;<span class="name">groupId</span>&gt;</span>org.springframework.cloud<span class="tag">&lt;/<span class="name">groupId</span>&gt;</span></span><br><span class="line">    <span class="tag">&lt;<span class="name">artifactId</span>&gt;</span>spring-cloud-starter-zipkin<span class="tag">&lt;/<span class="name">artifactId</span>&gt;</span></span><br><span class="line"><span class="tag">&lt;/<span class="name">dependency</span>&gt;</span></span><br></pre></td></tr></table></figure>

<blockquote>
<p>3、编写配置文件</p>
</blockquote>
<figure class="highlight yml"><table><tr><td class="code"><pre><span class="line"><span class="attr">spring:</span></span><br><span class="line">  <span class="attr">sleuth:</span></span><br><span class="line">    <span class="attr">sampler:</span></span><br><span class="line">      <span class="attr">probability:</span> <span class="number">1</span> <span class="comment">#百分之多少的sleuth信息需要输出到zipkin</span></span><br><span class="line">  <span class="attr">zipkin:</span></span><br><span class="line">    <span class="attr">base-url:</span> <span class="string">http://127.0.0.1:9411/</span>  <span class="comment">#指定zipkin的地址</span></span><br></pre></td></tr></table></figure>

<blockquote>
<p>4、测试</p>
</blockquote>
<p><img src="/posts/java/springcloud/1/images/image-20201113153443738.png" alt="image-20201113153443738"></p>
<h3 id="10-4-整合RabbitMQ"><a href="#10-4-整合RabbitMQ" class="headerlink" title="10.4 整合RabbitMQ"></a>10.4 整合RabbitMQ</h3><blockquote>
<p>1、导入RabbitMQ依赖（zipkin中已经依赖了RabbitMQ了）</p>
</blockquote>
<blockquote>
<p>2、修改配置文件</p>
</blockquote>
<figure class="highlight yml"><table><tr><td class="code"><pre><span class="line"><span class="attr">spring:</span></span><br><span class="line">  <span class="attr">zipkin:</span></span><br><span class="line">    <span class="attr">sender:</span></span><br><span class="line">      <span class="attr">type:</span> <span class="string">rabbit</span></span><br></pre></td></tr></table></figure>

<blockquote>
<p>3、修改Zipkin信息</p>
</blockquote>
<figure class="highlight yml"><table><tr><td class="code"><pre><span class="line"><span class="attr">version:</span> <span class="string">&quot;3.1&quot;</span></span><br><span class="line"><span class="attr">services:</span></span><br><span class="line">  <span class="attr">zipkin:</span></span><br><span class="line">    <span class="attr">image:</span> <span class="string">daocloud.io/daocloud/zipkin:latest</span></span><br><span class="line">    <span class="comment">#image: docker.io/openzipkin/zipkin:latest</span></span><br><span class="line">    <span class="attr">restart:</span> <span class="string">always</span></span><br><span class="line">    <span class="attr">container_name:</span> <span class="string">zipkin</span></span><br><span class="line">    <span class="attr">ports:</span></span><br><span class="line">    <span class="bullet">-</span> <span class="number">9411</span><span class="string">:9411</span></span><br><span class="line">    <span class="attr">environment:</span></span><br><span class="line">      <span class="bullet">-</span> <span class="string">RABBIT_ADDRESSES=10.27.10.123:5672</span> <span class="comment">#本地ipv4地址:端口</span></span><br><span class="line">      <span class="bullet">-</span> <span class="string">RABBIT_USER=test</span></span><br><span class="line">      <span class="bullet">-</span> <span class="string">RABBIT_PASSWORD=test</span></span><br><span class="line">      <span class="bullet">-</span> <span class="string">RABBIT_VIRTUAL_HOST=/test</span></span><br></pre></td></tr></table></figure>

<blockquote>
<p>3、测试</p>
</blockquote>
<p><img src="/posts/java/springcloud/1/images/image-20201113160658535.png" alt="image-20201113160658535"></p>
<p><img src="/posts/java/springcloud/1/images/image-20201113160724897.png" alt="image-20201113160724897"></p>
<h3 id="10-5-Zipkin存储数据到ES"><a href="#10-5-Zipkin存储数据到ES" class="headerlink" title="10.5  Zipkin存储数据到ES"></a>10.5  Zipkin存储数据到ES</h3><blockquote>
<p>1、重新修改zipkin的文件yml文件</p>
</blockquote>
<figure class="highlight yml"><table><tr><td class="code"><pre><span class="line"><span class="attr">version:</span> <span class="string">&quot;3.1&quot;</span></span><br><span class="line"><span class="attr">services:</span></span><br><span class="line">  <span class="attr">zipkin:</span></span><br><span class="line">    <span class="attr">image:</span> <span class="string">daocloud.io/daocloud/zipkin:latest</span></span><br><span class="line">    <span class="comment">#image: docker.io/openzipkin/zipkin:latest</span></span><br><span class="line">    <span class="attr">restart:</span> <span class="string">always</span></span><br><span class="line">    <span class="attr">container_name:</span> <span class="string">zipkin</span></span><br><span class="line">    <span class="attr">ports:</span></span><br><span class="line">    <span class="bullet">-</span> <span class="number">9411</span><span class="string">:9411</span></span><br><span class="line">    <span class="attr">environment:</span></span><br><span class="line">      <span class="bullet">-</span> <span class="string">RABBIT_ADDRESSES=10.27.10.123:5672</span></span><br><span class="line">      <span class="bullet">-</span> <span class="string">RABBIT_USER=test</span></span><br><span class="line">      <span class="bullet">-</span> <span class="string">RABBIT_PASSWORD=test</span></span><br><span class="line">      <span class="bullet">-</span> <span class="string">RABBIT_VIRTUAL_HOST=/test</span></span><br><span class="line">      <span class="bullet">-</span> <span class="string">STORAGE_TYPE=elasticsearch</span></span><br><span class="line">      <span class="bullet">-</span> <span class="string">ES_HOSTS=http://10.27.10.123:9200</span></span><br></pre></td></tr></table></figure>

<blockquote>
<p>2、安装Es</p>
</blockquote>
<figure class="highlight bash"><table><tr><td class="code"><pre><span class="line"> <span class="comment">#拉取镜像</span></span><br><span class="line"> docker pull elasticsearch</span><br><span class="line"> <span class="comment">#启动参数</span></span><br><span class="line"> docker run --name es1_6.6.0 \</span><br><span class="line">-p 9200:9200 \</span><br><span class="line">-p 9300:9300 \</span><br><span class="line">-e ES_JAVA_OPTS=<span class="string">&quot;-Xms256m -Xmx256m&quot;</span> \</span><br><span class="line">-v /d/elasticsearch/config/es1.yml:/usr/share/elasticsearch/config/elasticsearch.yml \</span><br><span class="line">-v /d/elasticsearch/data/es1:/usr/share/elasticsearch/data \</span><br><span class="line">-v /d/elasticsearch/logs/es1:/usr/share/elasticsearch/logs \</span><br><span class="line">-d 13aa43015aa1</span><br></pre></td></tr></table></figure>

<blockquote>
<p>3、安装kibana</p>
</blockquote>
<figure class="highlight bash"><table><tr><td class="code"><pre><span class="line"><span class="comment">#拉取kibana</span></span><br><span class="line">docker pull kibana</span><br><span class="line"><span class="comment">#启动参数</span></span><br><span class="line">docker run --name kibana6.6.0 -e ELASTICSEARCH_URL=http://10.27.10.123:9200 -p 5601:5601 -d dfc685453eaa</span><br></pre></td></tr></table></figure>

<p>创建索引</p>
<p><img src="/posts/java/springcloud/1/images/image-20201113164636525.png" alt="image-20201113164636525"></p>
<blockquote>
<p>4、重启zipkin后数据未丢失</p>
</blockquote>
<figure class="highlight bash"><table><tr><td class="code"><pre><span class="line">docker-compose restart</span><br></pre></td></tr></table></figure>

<blockquote>
<p>5、测试</p>
</blockquote>
<p><img src="/posts/java/springcloud/1/images/image-20201113164930192.png" alt="image-20201113164930192"></p>
<h2 id="十一、完整SpringCloud架构图"><a href="#十一、完整SpringCloud架构图" class="headerlink" title="十一、完整SpringCloud架构图"></a>十一、完整SpringCloud架构图</h2><p><img src="/posts/java/springcloud/1/images/image-20201113165759501.png" alt="image-20201113165759501"></p>
</article><div class="post-copyright"><div class="post-copyright__author"><span class="post-copyright-meta">文章作者: </span><span class="post-copyright-info"><a href="mailto:undefined">逝水无痕</a></span></div><div class="post-copyright__type"><span class="post-copyright-meta">文章链接: </span><span class="post-copyright-info"><a href="https://hexo.zyjblogs.cn/posts/java/springcloud/1.html">https://hexo.zyjblogs.cn/posts/java/springcloud/1.html</a></span></div><div class="post-copyright__notice"><span class="post-copyright-meta">版权声明: </span><span class="post-copyright-info">本博客所有文章除特别声明外，均采用 <a href="https://creativecommons.org/licenses/by-nc-sa/4.0/" target="_blank">CC BY-NC-SA 4.0</a> 许可协议。转载请注明来自 <a href="https://hexo.zyjblogs.cn" target="_blank">逝水无痕の博客</a>！</span></div></div><div class="tag_share"><div class="post-meta__tag-list"><a class="post-meta__tags" href="/tags/java/">java</a><a class="post-meta__tags" href="/tags/springcloud/">springcloud</a></div><div class="post_share"><div class="social-share" data-image="https://cdn.jsdelivr.net/npm/butterfly-extsrc@1/img/default.jpg" data-sites="facebook,twitter,wechat,weibo,qq"></div><link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/social-share.js/dist/css/share.min.css" media="print" onload="this.media='all'"><script src="https://cdn.jsdelivr.net/npm/social-share.js/dist/js/social-share.min.js" defer></script></div></div><nav class="pagination-post" id="pagination"><div class="prev-post pull-left"><a href="/posts/books/c/1.html"><img class="prev-cover" src="https://cdn.jsdelivr.net/npm/butterfly-extsrc@1/img/default.jpg" onerror="onerror=null;src='/img/404.jpg'" alt="cover of previous post"><div class="pagination-info"><div class="label">上一篇</div><div class="prev_info">C++书单</div></div></a></div><div class="next-post pull-right"><a href="/posts/helloword/1.html"><img class="next-cover" src="https://cdn.jsdelivr.net/npm/butterfly-extsrc@1/img/default.jpg" onerror="onerror=null;src='/img/404.jpg'" alt="cover of next post"><div class="pagination-info"><div class="label">下一篇</div><div class="next_info">第一次使用hexo</div></div></a></div></nav><div class="relatedPosts"><div class="headline"><i class="fas fa-thumbs-up fa-fw"></i><span> 相关推荐</span></div><div class="relatedPosts-list"><div><a href="/posts/java/base/net/1.html" title="BIO,NIO,AIO 总结"><img class="cover" src="https://cdn.jsdelivr.net/npm/butterfly-extsrc@1/img/default.jpg" alt="cover"><div class="content is-center"><div class="date"><i class="far fa-calendar-alt fa-fw"></i> 2021-08-13</div><div class="title">BIO,NIO,AIO 总结</div></div></a></div></div></div></div><div class="aside-content" id="aside-content"><div class="card-widget card-info"><div class="is-center"><div class="avatar-img"><img src="https://zyjblogs.cn/logo.jpg" onerror="this.onerror=null;this.src='/img/friend_404.gif'" alt="avatar"/></div><div class="author-info__name">逝水无痕</div><div class="author-info__description"></div></div><div class="card-info-data"><div class="card-info-data-item is-center"><a href="/archives/"><div class="headline">文章</div><div class="length-num">11</div></a></div><div class="card-info-data-item is-center"><a href="/tags/"><div class="headline">标签</div><div class="length-num">8</div></a></div><div class="card-info-data-item is-center"><a href="/categories/"><div class="headline">分类</div><div class="length-num">5</div></a></div></div><a class="button--animated" id="card-info-btn" target="_blank" rel="noopener" href="https://github.com/zyjnicemoe"><i class="fab fa-github"></i><span>Follow Me</span></a><div class="card-info-social-icons is-center"><a class="social-icon" href="https://github.com/zyjnicemoe" target="_blank" title="Github"><i class="fab fa-github"></i></a><a class="social-icon" href="mailto:1317453947@qq.com" target="_blank" title="Email"><i class="fas fa-envelope"></i></a><a class="social-icon" href="/atom.xml" target="_blank" title=""><i class="fas fa-rss"></i></a></div></div><div class="card-widget card-announcement"><div class="item-headline"><i class="fas fa-bullhorn card-announcement-animation"></i><span>公告</span></div><div class="announcement_content"><a target="_blank" rel="noopener" href="https://zyjblogs.cn">逝水无痕の博客https://zyjblogs.cn迁移到此</a></div></div><div class="sticky_layout"><div class="card-widget" id="card-toc"><div class="item-headline"><i class="fas fa-stream"></i><span>目录</span></div><div class="toc-content"><ol class="toc"><li class="toc-item toc-level-1"><a class="toc-link" href="#%E5%BE%AE%E6%9C%8D%E5%8A%A1%E6%A1%86%E6%9E%B6"><span class="toc-number">1.</span> <span class="toc-text">微服务框架</span></a><ol class="toc-child"><li class="toc-item toc-level-2"><a class="toc-link" href="#%E4%B8%80%E3%80%81SpringCloud%E4%BB%8B%E7%BB%8D"><span class="toc-number">1.1.</span> <span class="toc-text">一、SpringCloud介绍</span></a><ol class="toc-child"><li class="toc-item toc-level-3"><a class="toc-link" href="#1-1-%E5%BE%AE%E6%9C%8D%E5%8A%A1%E6%9E%B6%E6%9E%84"><span class="toc-number">1.1.1.</span> <span class="toc-text">1.1 微服务架构</span></a></li><li class="toc-item toc-level-3"><a class="toc-link" href="#1-2-SpringCloud%E4%BB%8B%E7%BB%8D"><span class="toc-number">1.1.2.</span> <span class="toc-text">1.2 SpringCloud介绍</span></a></li></ol></li><li class="toc-item toc-level-2"><a class="toc-link" href="#%E4%BA%8C%E3%80%81%E6%9C%8D%E5%8A%A1%E7%9A%84%E6%B3%A8%E5%86%8C%E4%B8%8E%E5%8F%91%E7%8E%B0-Eureka"><span class="toc-number">1.2.</span> <span class="toc-text">二、服务的注册与发现-Eureka</span></a><ol class="toc-child"><li class="toc-item toc-level-3"><a class="toc-link" href="#2-1-%E5%BC%95%E8%A8%80"><span class="toc-number">1.2.1.</span> <span class="toc-text">2.1 引言</span></a></li><li class="toc-item toc-level-3"><a class="toc-link" href="#2-2-Eureka%E7%9A%84%E5%BF%AB%E9%80%9F%E5%85%A5%E9%97%A8"><span class="toc-number">1.2.2.</span> <span class="toc-text">2.2 Eureka的快速入门</span></a><ol class="toc-child"><li class="toc-item toc-level-4"><a class="toc-link" href="#2-2-1-%E5%88%9B%E5%BB%BAEurekaServer"><span class="toc-number">1.2.2.1.</span> <span class="toc-text">2.2.1 创建EurekaServer</span></a></li><li class="toc-item toc-level-4"><a class="toc-link" href="#2-2-2-%E5%88%9B%E5%BB%BAEurekaClient"><span class="toc-number">1.2.2.2.</span> <span class="toc-text">2.2.2 创建EurekaClient</span></a></li><li class="toc-item toc-level-4"><a class="toc-link" href="#2-2-3-%E6%B5%8B%E8%AF%95Eureka"><span class="toc-number">1.2.2.3.</span> <span class="toc-text">2.2.3 测试Eureka</span></a></li></ol></li><li class="toc-item toc-level-3"><a class="toc-link" href="#2-3-Eureka%E7%9A%84%E5%AE%89%E5%85%A8%E6%80%A7"><span class="toc-number">1.2.3.</span> <span class="toc-text">2.3 Eureka的安全性</span></a></li><li class="toc-item toc-level-3"><a class="toc-link" href="#2-4-Eureka%E7%9A%84%E9%AB%98%E5%8F%AF%E7%94%A8%E6%80%A7"><span class="toc-number">1.2.4.</span> <span class="toc-text">2.4 Eureka的高可用性</span></a></li><li class="toc-item toc-level-3"><a class="toc-link" href="#2-5-Eureka%E7%9A%84%E7%BB%86%E8%8A%82"><span class="toc-number">1.2.5.</span> <span class="toc-text">2.5 Eureka的细节</span></a></li></ol></li><li class="toc-item toc-level-2"><a class="toc-link" href="#%E4%B8%89%E3%80%81%E6%9C%8D%E5%8A%A1%E9%97%B4%E7%9A%84%E8%B4%9F%E8%BD%BD%E5%9D%87%E8%A1%A1-Robbin"><span class="toc-number">1.3.</span> <span class="toc-text">三、服务间的负载均衡-Robbin</span></a><ol class="toc-child"><li class="toc-item toc-level-3"><a class="toc-link" href="#3-1-%E5%BC%95%E8%A8%80"><span class="toc-number">1.3.1.</span> <span class="toc-text">3.1 引言</span></a></li><li class="toc-item toc-level-3"><a class="toc-link" href="#3-2-Robbin%E7%9A%84%E5%BF%AB%E9%80%9F%E5%85%A5%E9%97%A8"><span class="toc-number">1.3.2.</span> <span class="toc-text">3.2 Robbin的快速入门</span></a></li><li class="toc-item toc-level-3"><a class="toc-link" href="#3-3-Robbin%E9%85%8D%E7%BD%AE%E8%B4%9F%E8%BD%BD%E5%9D%87%E8%A1%A1%E7%AD%96%E7%95%A5"><span class="toc-number">1.3.3.</span> <span class="toc-text">3.3 Robbin配置负载均衡策略</span></a></li></ol></li><li class="toc-item toc-level-2"><a class="toc-link" href="#%E5%9B%9B%E3%80%81%E6%9C%8D%E5%8A%A1%E9%97%B4%E7%9A%84%E8%B0%83%E7%94%A8-Feign"><span class="toc-number">1.4.</span> <span class="toc-text">四、服务间的调用-Feign</span></a><ol class="toc-child"><li class="toc-item toc-level-3"><a class="toc-link" href="#4-1-%E5%BC%95%E8%A8%80"><span class="toc-number">1.4.1.</span> <span class="toc-text">4.1 引言</span></a></li><li class="toc-item toc-level-3"><a class="toc-link" href="#4-2-Feign%E7%9A%84%E5%BF%AB%E9%80%9F%E5%85%A5%E9%97%A8"><span class="toc-number">1.4.2.</span> <span class="toc-text">4.2 Feign的快速入门</span></a></li><li class="toc-item toc-level-3"><a class="toc-link" href="#4-3-Feign%E7%9A%84%E4%BC%A0%E9%80%92%E5%8F%82%E6%95%B0%E6%96%B9%E5%BC%8F"><span class="toc-number">1.4.3.</span> <span class="toc-text">4.3 Feign的传递参数方式</span></a></li><li class="toc-item toc-level-3"><a class="toc-link" href="#4-4-Feign%E7%9A%84Fallback"><span class="toc-number">1.4.4.</span> <span class="toc-text">4.4 Feign的Fallback</span></a></li></ol></li><li class="toc-item toc-level-2"><a class="toc-link" href="#%E4%BA%94%E3%80%81%E6%9C%8D%E5%8A%A1%E7%9A%84%E9%9A%94%E7%A6%BB%E5%8F%8A%E7%86%94%E6%96%AD%E5%99%A8-Hystrix"><span class="toc-number">1.5.</span> <span class="toc-text">五、服务的隔离及熔断器-Hystrix</span></a><ol class="toc-child"><li class="toc-item toc-level-3"><a class="toc-link" href="#5-1-%E5%BC%95%E8%A8%80"><span class="toc-number">1.5.1.</span> <span class="toc-text">5.1 引言</span></a></li><li class="toc-item toc-level-3"><a class="toc-link" href="#5-2-%E9%99%8D%E7%BA%A7%E6%9C%BA%E5%88%B6%E5%AE%9E%E7%8E%B0"><span class="toc-number">1.5.2.</span> <span class="toc-text">5.2 降级机制实现</span></a></li><li class="toc-item toc-level-3"><a class="toc-link" href="#5-3-%E7%BA%BF%E7%A8%8B%E9%9A%94%E7%A6%BB"><span class="toc-number">1.5.3.</span> <span class="toc-text">5.3 线程隔离</span></a></li><li class="toc-item toc-level-3"><a class="toc-link" href="#5-4-%E6%96%AD%E8%B7%AF%E5%99%A8"><span class="toc-number">1.5.4.</span> <span class="toc-text">5.4 断路器</span></a><ol class="toc-child"><li class="toc-item toc-level-4"><a class="toc-link" href="#5-4-1-%E6%96%AD%E8%B7%AF%E5%99%A8%E4%BB%8B%E7%BB%8D"><span class="toc-number">1.5.4.1.</span> <span class="toc-text">5.4.1 断路器介绍</span></a></li><li class="toc-item toc-level-4"><a class="toc-link" href="#5-4-2-%E9%85%8D%E7%BD%AE%E6%96%AD%E8%B7%AF%E5%99%A8%E7%9A%84%E7%9B%91%E6%8E%A7%E7%95%8C%E9%9D%A2"><span class="toc-number">1.5.4.2.</span> <span class="toc-text">5.4.2 配置断路器的监控界面</span></a></li><li class="toc-item toc-level-4"><a class="toc-link" href="#5-4-3-%E9%85%8D%E7%BD%AE%E6%96%AD%E8%B7%AF%E5%99%A8%E7%9A%84%E5%B1%9E%E6%80%A7"><span class="toc-number">1.5.4.3.</span> <span class="toc-text">5.4.3 配置断路器的属性</span></a></li></ol></li><li class="toc-item toc-level-3"><a class="toc-link" href="#5-5-%E8%AF%B7%E6%B1%82%E7%BC%93%E5%AD%98"><span class="toc-number">1.5.5.</span> <span class="toc-text">5.5 请求缓存</span></a><ol class="toc-child"><li class="toc-item toc-level-4"><a class="toc-link" href="#5-5-1-%E8%AF%B7%E6%B1%82%E7%BC%93%E5%AD%98%E7%9A%84%E4%BB%8B%E7%BB%8D"><span class="toc-number">1.5.5.1.</span> <span class="toc-text">5.5.1 请求缓存的介绍</span></a></li><li class="toc-item toc-level-4"><a class="toc-link" href="#5-5-2-%E8%AF%B7%E6%B1%82%E7%BC%93%E5%AD%98%E7%9A%84%E5%AE%9E%E7%8E%B0"><span class="toc-number">1.5.5.2.</span> <span class="toc-text">5.5.2 请求缓存的实现</span></a></li></ol></li></ol></li><li class="toc-item toc-level-2"><a class="toc-link" href="#%E5%85%AD%E3%80%81%E6%9C%8D%E5%8A%A1%E7%9A%84%E7%BD%91%E5%85%B3-Zuul"><span class="toc-number">1.6.</span> <span class="toc-text">六、服务的网关-Zuul</span></a><ol class="toc-child"><li class="toc-item toc-level-3"><a class="toc-link" href="#6-1-%E5%BC%95%E8%A8%80"><span class="toc-number">1.6.1.</span> <span class="toc-text">6.1 引言</span></a></li><li class="toc-item toc-level-3"><a class="toc-link" href="#6-2-Zuul%E7%9A%84%E5%BF%AB%E9%80%9F%E5%85%A5%E9%97%A8"><span class="toc-number">1.6.2.</span> <span class="toc-text">6.2 Zuul的快速入门</span></a></li><li class="toc-item toc-level-3"><a class="toc-link" href="#6-3-Zuul%E5%B8%B8%E7%94%A8%E9%85%8D%E7%BD%AE%E4%BF%A1%E6%81%AF"><span class="toc-number">1.6.3.</span> <span class="toc-text">6.3  Zuul常用配置信息</span></a><ol class="toc-child"><li class="toc-item toc-level-4"><a class="toc-link" href="#6-3-1-Zuul%E7%9A%84%E7%9B%91%E6%8E%A7%E7%95%8C%E9%9D%A2"><span class="toc-number">1.6.3.1.</span> <span class="toc-text">6.3.1 Zuul的监控界面</span></a></li><li class="toc-item toc-level-4"><a class="toc-link" href="#6-3-2-%E5%BF%BD%E7%95%A5%E6%9C%8D%E5%8A%A1%E8%AE%BE%E7%BD%AE"><span class="toc-number">1.6.3.2.</span> <span class="toc-text">6.3.2 忽略服务设置</span></a></li><li class="toc-item toc-level-4"><a class="toc-link" href="#6-3-3-%E8%87%AA%E5%AE%9A%E4%B9%89%E6%9C%8D%E5%8A%A1%E9%85%8D%E7%BD%AE"><span class="toc-number">1.6.3.3.</span> <span class="toc-text">6.3.3 自定义服务配置</span></a></li><li class="toc-item toc-level-4"><a class="toc-link" href="#6-3-4-%E7%81%B0%E5%BA%A6%E5%8F%91%E5%B8%83"><span class="toc-number">1.6.3.4.</span> <span class="toc-text">6.3.4 灰度发布</span></a></li></ol></li><li class="toc-item toc-level-3"><a class="toc-link" href="#6-4-Zuul%E7%9A%84%E8%BF%87%E6%BB%A4%E5%99%A8%E6%89%A7%E8%A1%8C%E6%B5%81%E7%A8%8B"><span class="toc-number">1.6.4.</span> <span class="toc-text">6.4 Zuul的过滤器执行流程</span></a></li><li class="toc-item toc-level-3"><a class="toc-link" href="#6-5-Zuul%E8%BF%87%E6%BB%A4%E5%99%A8%E5%85%A5%E9%97%A8"><span class="toc-number">1.6.5.</span> <span class="toc-text">6.5 Zuul过滤器入门</span></a></li><li class="toc-item toc-level-3"><a class="toc-link" href="#6-6-PreFilter%E5%AE%9E%E7%8E%B0token%E6%A0%A1%E9%AA%8C"><span class="toc-number">1.6.6.</span> <span class="toc-text">6.6 PreFilter实现token校验</span></a></li><li class="toc-item toc-level-3"><a class="toc-link" href="#6-7-Zuul%E7%9A%84%E9%99%8D%E7%BA%A7"><span class="toc-number">1.6.7.</span> <span class="toc-text">6.7 Zuul的降级</span></a></li><li class="toc-item toc-level-3"><a class="toc-link" href="#6-8-Zuul%E5%8A%A8%E6%80%81%E8%B7%AF%E7%94%B1"><span class="toc-number">1.6.8.</span> <span class="toc-text">6.8 Zuul动态路由</span></a></li></ol></li><li class="toc-item toc-level-2"><a class="toc-link" href="#%E4%B8%83%E3%80%81%E5%A4%9A%E8%AF%AD%E8%A8%80%E6%94%AF%E6%8C%81-Sidecar"><span class="toc-number">1.7.</span> <span class="toc-text">七、多语言支持-Sidecar</span></a><ol class="toc-child"><li class="toc-item toc-level-3"><a class="toc-link" href="#7-1-%E5%BC%95%E8%A8%80"><span class="toc-number">1.7.1.</span> <span class="toc-text">7.1 引言</span></a></li><li class="toc-item toc-level-3"><a class="toc-link" href="#7-2-Sidecar%E5%AE%9E%E7%8E%B0"><span class="toc-number">1.7.2.</span> <span class="toc-text">7.2 Sidecar实现</span></a></li></ol></li><li class="toc-item toc-level-2"><a class="toc-link" href="#%E5%85%AB%E3%80%81%E6%9C%8D%E5%8A%A1%E9%97%B4%E6%B6%88%E6%81%AF%E4%BC%A0%E9%80%92-Stream"><span class="toc-number">1.8.</span> <span class="toc-text">八、服务间消息传递-Stream</span></a><ol class="toc-child"><li class="toc-item toc-level-3"><a class="toc-link" href="#8-1-%E5%BC%95%E8%A8%80"><span class="toc-number">1.8.1.</span> <span class="toc-text">8.1 引言</span></a></li><li class="toc-item toc-level-3"><a class="toc-link" href="#8-2-Stream%E5%BF%AB%E9%80%9F%E5%85%A5%E9%97%A8"><span class="toc-number">1.8.2.</span> <span class="toc-text">8.2 Stream快速入门</span></a></li><li class="toc-item toc-level-3"><a class="toc-link" href="#8-3-Stream%E9%87%8D%E5%A4%8D%E6%B6%88%E8%B4%B9%E9%97%AE%E9%A2%98"><span class="toc-number">1.8.3.</span> <span class="toc-text">8.3 Stream重复消费问题</span></a></li><li class="toc-item toc-level-3"><a class="toc-link" href="#8-4-Stream%E7%9A%84%E6%B6%88%E8%B4%B9%E8%80%85%E6%89%8B%E5%8A%A8ack"><span class="toc-number">1.8.4.</span> <span class="toc-text">8.4 Stream的消费者手动ack</span></a></li></ol></li><li class="toc-item toc-level-2"><a class="toc-link" href="#%E4%B9%9D%E3%80%81%E6%9C%8D%E5%8A%A1%E7%9A%84%E5%8A%A8%E6%80%81%E9%85%8D%E7%BD%AE-Config"><span class="toc-number">1.9.</span> <span class="toc-text">九、服务的动态配置-Config</span></a><ol class="toc-child"><li class="toc-item toc-level-3"><a class="toc-link" href="#9-1-%E5%BC%95%E8%A8%80"><span class="toc-number">1.9.1.</span> <span class="toc-text">9.1 引言</span></a></li><li class="toc-item toc-level-3"><a class="toc-link" href="#9-2-%E6%90%AD%E5%BB%BAConfig-Server"><span class="toc-number">1.9.2.</span> <span class="toc-text">9.2 搭建Config-Server</span></a></li><li class="toc-item toc-level-3"><a class="toc-link" href="#9-3%E3%80%81%E4%BF%AE%E6%94%B9Customer%E8%BF%9E%E6%8E%A5Config"><span class="toc-number">1.9.3.</span> <span class="toc-text">9.3、修改Customer连接Config</span></a></li><li class="toc-item toc-level-3"><a class="toc-link" href="#9-4-%E5%AE%9E%E7%8E%B0%E5%8A%A8%E6%80%81%E9%85%8D%E7%BD%AE"><span class="toc-number">1.9.4.</span> <span class="toc-text">9.4 实现动态配置</span></a><ol class="toc-child"><li class="toc-item toc-level-4"><a class="toc-link" href="#9-4-1-%E5%AE%9E%E7%8E%B0%E5%8E%9F%E7%90%86"><span class="toc-number">1.9.4.1.</span> <span class="toc-text">9.4.1 实现原理</span></a></li><li class="toc-item toc-level-4"><a class="toc-link" href="#9-4-2-%E6%9C%8D%E5%8A%A1%E8%BF%9E%E6%8E%A5RabbitMQ"><span class="toc-number">1.9.4.2.</span> <span class="toc-text">9.4.2 服务连接RabbitMQ</span></a></li><li class="toc-item toc-level-4"><a class="toc-link" href="#9-4-3-%E5%AE%9E%E7%8E%B0%E6%89%8B%E5%8A%A8%E5%88%B7%E6%96%B0"><span class="toc-number">1.9.4.3.</span> <span class="toc-text">9.4.3 实现手动刷新</span></a></li><li class="toc-item toc-level-4"><a class="toc-link" href="#9-4-4-%E5%86%85%E7%BD%91%E7%A9%BF%E9%80%8F"><span class="toc-number">1.9.4.4.</span> <span class="toc-text">9.4.4 内网穿透</span></a></li><li class="toc-item toc-level-4"><a class="toc-link" href="#9-4-5-%E5%AE%9E%E7%8E%B0%E8%87%AA%E5%8A%A8%E5%88%B7%E6%96%B0%E9%85%8D%E7%BD%AE"><span class="toc-number">1.9.4.5.</span> <span class="toc-text">9.4.5 实现自动刷新配置</span></a></li></ol></li></ol></li><li class="toc-item toc-level-2"><a class="toc-link" href="#%E5%8D%81%E3%80%81%E6%9C%8D%E5%8A%A1%E7%9A%84%E8%BF%BD%E8%B8%AA-Sleuth"><span class="toc-number">1.10.</span> <span class="toc-text">十、服务的追踪-Sleuth</span></a><ol class="toc-child"><li class="toc-item toc-level-3"><a class="toc-link" href="#10-1-%E5%BC%95%E8%A8%80"><span class="toc-number">1.10.1.</span> <span class="toc-text">10.1 引言</span></a></li><li class="toc-item toc-level-3"><a class="toc-link" href="#10-2-Sleuth%E4%BD%BF%E7%94%A8"><span class="toc-number">1.10.2.</span> <span class="toc-text">10.2 Sleuth使用</span></a></li><li class="toc-item toc-level-3"><a class="toc-link" href="#10-3-Zipkin%E7%9A%84%E4%BD%BF%E7%94%A8"><span class="toc-number">1.10.3.</span> <span class="toc-text">10.3 Zipkin的使用</span></a></li><li class="toc-item toc-level-3"><a class="toc-link" href="#10-4-%E6%95%B4%E5%90%88RabbitMQ"><span class="toc-number">1.10.4.</span> <span class="toc-text">10.4 整合RabbitMQ</span></a></li><li class="toc-item toc-level-3"><a class="toc-link" href="#10-5-Zipkin%E5%AD%98%E5%82%A8%E6%95%B0%E6%8D%AE%E5%88%B0ES"><span class="toc-number">1.10.5.</span> <span class="toc-text">10.5  Zipkin存储数据到ES</span></a></li></ol></li><li class="toc-item toc-level-2"><a class="toc-link" href="#%E5%8D%81%E4%B8%80%E3%80%81%E5%AE%8C%E6%95%B4SpringCloud%E6%9E%B6%E6%9E%84%E5%9B%BE"><span class="toc-number">1.11.</span> <span class="toc-text">十一、完整SpringCloud架构图</span></a></li></ol></li></ol></div></div><div class="card-widget card-recent-post"><div class="item-headline"><i class="fas fa-history"></i><span>最新文章</span></div><div class="aside-list"><div class="aside-list-item"><a class="thumbnail" href="/posts/c++/base/polymorphic/1.html" title="C++编译期多态与运行期多态"><img src="https://cdn.jsdelivr.net/npm/butterfly-extsrc@1/img/default.jpg" onerror="this.onerror=null;this.src='/img/404.jpg'" alt="C++编译期多态与运行期多态"/></a><div class="content"><a class="title" href="/posts/c++/base/polymorphic/1.html" title="C++编译期多态与运行期多态">C++编译期多态与运行期多态</a><time datetime="2022-02-06T16:00:00.000Z" title="发表于 2022-02-07 00:00:00">2022-02-07</time></div></div><div class="aside-list-item"><a class="thumbnail" href="/posts/c++/base/virtual/1.html" title="虚基类"><img src="https://cdn.jsdelivr.net/npm/butterfly-extsrc@1/img/default.jpg" onerror="this.onerror=null;this.src='/img/404.jpg'" alt="虚基类"/></a><div class="content"><a class="title" href="/posts/c++/base/virtual/1.html" title="虚基类">虚基类</a><time datetime="2022-02-06T16:00:00.000Z" title="发表于 2022-02-07 00:00:00">2022-02-07</time></div></div><div class="aside-list-item"><a class="thumbnail" href="/posts/c++/library/json/1.html" title="C/C++ 关于 cJson 库的使用"><img src="https://cdn.jsdelivr.net/npm/butterfly-extsrc@1/img/default.jpg" onerror="this.onerror=null;this.src='/img/404.jpg'" alt="C/C++ 关于 cJson 库的使用"/></a><div class="content"><a class="title" href="/posts/c++/library/json/1.html" title="C/C++ 关于 cJson 库的使用">C/C++ 关于 cJson 库的使用</a><time datetime="2022-02-06T16:00:00.000Z" title="发表于 2022-02-07 00:00:00">2022-02-07</time></div></div><div class="aside-list-item"><a class="thumbnail" href="/posts/c++/study/backend/1.html" title="C++后台"><img src="https://cdn.jsdelivr.net/npm/butterfly-extsrc@1/img/default.jpg" onerror="this.onerror=null;this.src='/img/404.jpg'" alt="C++后台"/></a><div class="content"><a class="title" href="/posts/c++/study/backend/1.html" title="C++后台">C++后台</a><time datetime="2022-02-06T16:00:00.000Z" title="发表于 2022-02-07 00:00:00">2022-02-07</time></div></div><div class="aside-list-item"><a class="thumbnail" href="/posts/c++/library/date/1.html" title="C++ 使用 chrono 库处理日期和时间"><img src="https://cdn.jsdelivr.net/npm/butterfly-extsrc@1/img/default.jpg" onerror="this.onerror=null;this.src='/img/404.jpg'" alt="C++ 使用 chrono 库处理日期和时间"/></a><div class="content"><a class="title" href="/posts/c++/library/date/1.html" title="C++ 使用 chrono 库处理日期和时间">C++ 使用 chrono 库处理日期和时间</a><time datetime="2022-02-06T16:00:00.000Z" title="发表于 2022-02-07 00:00:00">2022-02-07</time></div></div></div></div></div></div></main><footer id="footer"><div id="footer-wrap"><div class="copyright">&copy;2019 - 2022 By 逝水无痕</div><div class="framework-info"><span>框架 </span><a target="_blank" rel="noopener" href="https://hexo.io">Hexo</a><span class="footer-separator">|</span><span>主题 </span><a target="_blank" rel="noopener" href="https://github.com/jerryc127/hexo-theme-butterfly">Butterfly</a></div><div class="footer_custom_text"><div><img style="padding-top:2px" src="https://sp-ao.shortpixel.ai/client/q_glossy,ret_img/https://zyjblogs.cn/img/icp.png"><a class="banquan" style="color:#000" href="http://www.beian.gov.cn/portal/registerSystemInfo?recordcode=鄂ICP备19023232号" target="_blank" data-pjax-state="">鄂ICP备19023232号</a></div></div></div></footer></div><div id="rightside"><div id="rightside-config-hide"><button id="readmode" type="button" title="阅读模式"><i class="fas fa-book-open"></i></button><button id="darkmode" type="button" title="浅色和深色模式转换"><i class="fas fa-adjust"></i></button><button id="hide-aside-btn" type="button" title="单栏和双栏切换"><i class="fas fa-arrows-alt-h"></i></button></div><div id="rightside-config-show"><button id="rightside_config" type="button" title="设置"><i class="fas fa-cog fa-spin"></i></button><button class="close" id="mobile-toc-button" type="button" title="目录"><i class="fas fa-list-ul"></i></button><button id="go-up" type="button" title="回到顶部"><i class="fas fa-arrow-up"></i></button></div></div><div id="local-search"><div class="search-dialog"><div class="search-dialog__title" id="local-search-title">本地搜索</div><div id="local-input-panel"><div id="local-search-input"><div class="local-search-box"><input class="local-search-box--input" placeholder="搜索文章" type="text"/></div></div></div><hr/><div id="local-search-results"></div><span class="search-close-button"><i class="fas fa-times"></i></span></div><div id="search-mask"></div></div><div><script src="/js/utils.js"></script><script src="/js/main.js"></script><script src="https://cdn.jsdelivr.net/npm/node-snackbar/dist/snackbar.min.js"></script><script src="/js/search/local-search.js"></script><script>var preloader = {
  endLoading: () => {
    document.body.style.overflow = 'auto';
    document.getElementById('loading-box').classList.add("loaded")
  },
  initLoading: () => {
    document.body.style.overflow = '';
    document.getElementById('loading-box').classList.remove("loaded")

  }
}
window.addEventListener('load',preloader.endLoading())</script><div class="js-pjax"></div><script src="https://cdn.jsdelivr.net/npm/butterfly-extsrc@1/dist/activate-power-mode.min.js"></script><script>POWERMODE.colorful = true;
POWERMODE.shake = true;
POWERMODE.mobile = false;
document.body.addEventListener('input', POWERMODE);
</script><script src="https://cdn.jsdelivr.net/npm/pjax/pjax.min.js"></script><script>let pjaxSelectors = [
  'title',
  '#config-diff',
  '#body-wrap',
  '#rightside-config-hide',
  '#rightside-config-show',
  '.js-pjax'
]

if (false) {
  pjaxSelectors.unshift('meta[property="og:image"]', 'meta[property="og:title"]', 'meta[property="og:url"]')
}

var pjax = new Pjax({
  elements: 'a:not([target="_blank"]):not([href="/music/"]):not([href="/no-pjax/"])',
  selectors: pjaxSelectors,
  cacheBust: false,
  analytics: false,
  scrollRestoration: false
})

document.addEventListener('pjax:send', function () {

  // removeEventListener scroll 
  window.removeEventListener('scroll', window.tocScrollFn)
  window.removeEventListener('scroll', scrollCollect)

  typeof preloader === 'object' && preloader.initLoading()
  
  if (window.aplayers) {
    for (let i = 0; i < window.aplayers.length; i++) {
      if (!window.aplayers[i].options.fixed) {
        window.aplayers[i].destroy()
      }
    }
  }

  typeof typed === 'object' && typed.destroy()

  //reset readmode
  const $bodyClassList = document.body.classList
  $bodyClassList.contains('read-mode') && $bodyClassList.remove('read-mode')

})

document.addEventListener('pjax:complete', function () {
  window.refreshFn()

  document.querySelectorAll('script[data-pjax]').forEach(item => {
    const newScript = document.createElement('script')
    const content = item.text || item.textContent || item.innerHTML || ""
    Array.from(item.attributes).forEach(attr => newScript.setAttribute(attr.name, attr.value))
    newScript.appendChild(document.createTextNode(content))
    item.parentNode.replaceChild(newScript, item)
  })

  GLOBAL_CONFIG.islazyload && window.lazyLoadInstance.update()

  typeof chatBtnFn === 'function' && chatBtnFn()
  typeof panguInit === 'function' && panguInit()

  // google analytics
  typeof gtag === 'function' && gtag('config', '', {'page_path': window.location.pathname});

  // baidu analytics
  typeof _hmt === 'object' && _hmt.push(['_trackPageview',window.location.pathname]);

  typeof loadMeting === 'function' && document.getElementsByClassName('aplayer').length && loadMeting()

  // Analytics
  if (false) {
    MtaH5.pgv()
  }

  // prismjs
  typeof Prism === 'object' && Prism.highlightAll()

  typeof preloader === 'object' && preloader.endLoading()
})

document.addEventListener('pjax:error', (e) => {
  if (e.request.status === 404) {
    pjax.loadUrl('/404.html')
  }
})</script><script async data-pjax src="//busuanzi.ibruce.info/busuanzi/2.3/busuanzi.pure.mini.js"></script></div></body></html>